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

# Verifying Webhook Signatures

> Verify HMAC-SHA256 signatures to ensure webhook payloads originate from Wirebox.

If you choose not to use a Custom Auth Token, or if your compliance requirements mandate zero-trust payload verification, you can verify incoming requests using the HMAC-SHA256 signature in the `X-Wirebox-Signature-256` header.

***

### The Signature Header Format

The header contains a timestamp `t` and one or more signatures `v1`:

```http theme={null}
X-Wirebox-Signature-256: t=1726051200,v1=a1b2c3d4e5f6...
```

The signed payload is computed as:

```text theme={null}
string_to_sign = "t=" + timestamp + "." + raw_request_body
```

***

### Node.js Verification Example

<CodeGroup>
  ```ts Node.js (TypeScript) theme={null}
  import crypto from "crypto";

  export function verifyWireboxSignature(
    rawBody: string,
    signatureHeader: string,
    secret: string,
    toleranceSeconds: number = 300
  ): boolean {
    // 1. Parse header components
    const elements = signatureHeader.split(",");
    let timestamp: string | null = null;
    const signatures: string[] = [];

    for (const element of elements) {
      const [key, value] = element.trim().split("=");
      if (key === "t") timestamp = value;
      if (key === "v1") signatures.push(value);
    }

    if (!timestamp || signatures.length === 0) return false;

    // 2. Prevent replay attacks (5-minute tolerance)
    const currentTime = Math.floor(Date.now() / 1000);
    if (Math.abs(currentTime - parseInt(timestamp, 10)) > toleranceSeconds) {
      return false;
    }

    // 3. Compute expected signature
    const payloadToSign = `t=${timestamp}.${rawBody}`;
    const expectedSignature = crypto
      .createHmac("sha256", secret)
      .update(payloadToSign, "utf8")
      .digest("hex");

    // 4. Constant-time comparison
    for (const sig of signatures) {
      if (
        crypto.timingSafeEqual(
          Buffer.from(sig, "hex"),
          Buffer.from(expectedSignature, "hex")
        )
      ) {
        return true;
      }
    }

    return false;
  }
  ```

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

  def verify_wirebox_signature(raw_body: str, signature_header: str, secret: str, tolerance: int = 300) -> bool:
      pairs = dict(item.strip().split("=") for item in signature_header.split(","))
      timestamp = pairs.get("t")
      v1_signature = pairs.get("v1")

      if not timestamp or not v1_signature:
          return False

      # Check timestamp freshness
      if abs(time.time() - int(timestamp)) > tolerance:
          return False

      # Calculate HMAC
      string_to_sign = f"t={timestamp}.{rawBody}".encode("utf-8")
      expected = hmac.new(secret.encode("utf-8"), string_to_sign, hashlib.sha256).hexdigest()

      return hmac.compare_digest(v1_signature, expected)
  ```
</CodeGroup>
