> ## Documentation Index
> Fetch the complete documentation index at: https://learn.nexudus.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Validating sensor data

> Learn how to use a shared secret to validate the sensor data sent to a sensor endpoint.

# ✔️ Validate incoming data

Learn how to use a shared secret so we can validate the sensor data sent to a sensor endpoint.

If the data strategy selected for a sensor is **Endpoint**, Nexudus waits for data to be sent to that endpoint. To validate this data actually originates from a trusted source, a shared secret is used to sign the request.

A shared secret is automatically created for you when you register a new sensor. You can view and rotate this secret if needed within the details of each sensor.

## How signature validation works

To validate the signature of a request, we serialise the payload of the request and calculate a **HMACSHA256** signature using the shared secret. We will compare that signature with the value of the HTTP header `X-Nexudus-Hook-Signature` and only accept the request if there is an exact match.

> [!NOTE]
>
> Both the payload and shared secrets are converted to a byte array assuming **UTF-8** encoding. You may need to take this into consideration when
> computing the signature on your server in order to set the HTTP header.

## Code examples

```csharp C# theme={null}
var SIGNATURE_HEADER_NAME = "X-Nexudus-Hook-Signature";
var payload = Newtonsoft.Json.JsonConvert.SerializeObject(data);
if (payload == null) return Unauthorized();

var receivedHash = Request.Headers.GetValues(SIGNATURE_HEADER_NAME).FirstOrDefault();
if (receivedHash == null) return Unauthorized();

var keyByte = new UTF8Encoding().GetBytes(sharedSecret);
var messageBytes = new UTF8Encoding().GetBytes(payload);

var hmacsha256 = new HMACSHA256(keyByte);
var hashBytes = hmacsha256.ComputeHash(messageBytes);
var hash = ConvertByteToString(hashBytes);

if (hash != receivedHash)
    return Unauthorized();
```

```python Python theme={null}
import hmac
import hashlib
import json

SIGNATURE_HEADER_NAME = "X-Nexudus-Hook-Signature"

def validate_sensor_data(request, shared_secret):
    payload = json.dumps(request.json, separators=(",", ":"))
    if payload is None:
        return False

    received_hash = request.headers.get(SIGNATURE_HEADER_NAME)
    if received_hash is None:
        return False

    computed_hash = hmac.new(
        shared_secret.encode("utf-8"),
        payload.encode("utf-8"),
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(computed_hash, received_hash)
```

```javascript Node.js theme={null}
const crypto = require('crypto')

const SIGNATURE_HEADER_NAME = 'X-Nexudus-Hook-Signature'

function validateSensorData(req, sharedSecret) {
  const payload = JSON.stringify(req.body)
  if (!payload) return false

  const receivedHash = req.headers[SIGNATURE_HEADER_NAME.toLowerCase()]
  if (!receivedHash) return false

  const computedHash = crypto.createHmac('sha256', Buffer.from(sharedSecret, 'utf-8')).update(Buffer.from(payload, 'utf-8')).digest('hex')

  return crypto.timingSafeEqual(Buffer.from(computedHash), Buffer.from(receivedHash))
}
```

```java Java theme={null}
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

public class SensorValidator {

    private static final String SIGNATURE_HEADER_NAME = "X-Nexudus-Hook-Signature";

    public static boolean validate(String payload, String receivedHash, String sharedSecret) {
        if (payload == null || receivedHash == null) return false;

        try {
            Mac hmac = Mac.getInstance("HmacSHA256");
            SecretKeySpec keySpec = new SecretKeySpec(
                sharedSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"
            );
            hmac.init(keySpec);
            byte[] hashBytes = hmac.doFinal(payload.getBytes(StandardCharsets.UTF_8));

            StringBuilder sb = new StringBuilder();
            for (byte b : hashBytes) {
                sb.append(String.format("%02x", b));
            }

            return sb.toString().equals(receivedHash);
        } catch (Exception e) {
            return false;
        }
    }
}
```

```ruby Ruby theme={null}
require "openssl"
require "json"

SIGNATURE_HEADER_NAME = "X-Nexudus-Hook-Signature"

def validate_sensor_data(request, shared_secret)
  payload = request.body.read
  return false if payload.nil? || payload.empty?

  received_hash = request.env["HTTP_X_NEXUDUS_HOOK_SIGNATURE"]
  return false if received_hash.nil?

  computed_hash = OpenSSL::HMAC.hexdigest(
    "SHA256",
    shared_secret.encode("utf-8"),
    payload.encode("utf-8")
  )

  Rack::Utils.secure_compare(computed_hash, received_hash)
end
```

```php PHP theme={null}
<?php

$SIGNATURE_HEADER_NAME = "X-Nexudus-Hook-Signature";

function validateSensorData(string $payload, string $sharedSecret): bool
{
    $receivedHash = $_SERVER["HTTP_X_NEXUDUS_HOOK_SIGNATURE"] ?? null;
    if ($receivedHash === null || $payload === "") {
        return false;
    }

    $computedHash = hash_hmac("sha256", $payload, $sharedSecret);

    return hash_equals($computedHash, $receivedHash);
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.