Skip to Content
ComplianceAuthenticate Webhooks

Authenticate Webhook Payloads

Securely validate webhook events sent from Reflex using HMAC-SHA256 signatures.

Overview

Webhook secrets provide a way to verify that incoming webhook requests really originate from Reflex. Each team has a unique webhook_secret that is used for signing webhook events.

When an event is triggered, Reflex sends a POST request to the configured webhook URL with an Amboss-Secret header. This header contains an HMAC-SHA256 signature of the webhook payload, signed using the webhook_secret.

Retrieving Webhook Secret

To validate webhook requests, you need your webhook_secret. You can retrieve it using the following GraphQL query or directly in the settings view  in Reflex.

Webhook Settings

Validating Webhook Requests

Read the signature header

Ensure that the Amboss-Secret header is present in the request and retrieve it.

Compute the expected hash

Compute an HMAC-SHA256 hash of the request payload using your webhook_secret.

Compare

Compare the computed hash with the Amboss-Secret header value sent by Reflex. If they match, the webhook is authentic.

How to Compute the Hash

verify.js
const crypto = require("crypto"); function computeHash(webhook_payload, webhook_secret) { const hash = crypto .createHmac("sha256", webhook_secret) .update(Buffer.from(JSON.stringify(webhook_payload), "utf8")) .digest("hex") .toLowerCase(); return hash; }

Each computeHash() function:

  • Generates an HMAC-SHA256 hash of the received payload using your webhook_secret.
  • Encodes the payload consistently by converting it to a UTF-8 JSON string before hashing.
  • Returns the final hash so it can be compared against the Amboss-Secret header.

If both hashes match, the webhook is verified as authentic. Otherwise, the request should be rejected as it might have been altered or sent by an unauthorized source.

Example

You can use this example to validate your hashing logic.

Webhook Secret

df21d54f-618a-4dce-b796-be1ea0ee6716

Webhook Payload

payload.json
{ "event": "WORKFLOW_RESULT", "payload": { "workflow_run_id": "12345", "template": { "id": "temp_987", "name": "Data Processing Workflow", "description": "Processes incoming data and generates reports." }, "created_at": "2024-02-12T10:15:30Z", "finished_at": "2024-02-12T10:45:00Z", "status": "COMPLETED", "jobs": [ { "id": "job_001", "created_at": "2024-02-12T10:16:00Z", "finished_at": "2024-02-12T10:30:00Z", "job_name": "Data Ingestion", "status": "SUCCESS" } ], "inputs": [ { "input_name": "dataset_url", "value": "https://example.com/dataset.csv" } ] } }

Computed HMAC-SHA256 Hash

8548e12b87d55549d2ef9c1f11e4afe00c56ccbd1528fa4a2d654fd6ef998609

Checks

  • This computed hash should be compared with the value of the Amboss-Secret header.
  • If both values match, it confirms that the request is authentic and unaltered, ensuring that it was sent by Reflex and not modified in transit.
  • If they do not match, the request should be rejected as it may have been tampered with or sent by an unauthorized source.

Troubleshooting

The HMAC signature is tied to the exact byte sequence of the request body.During parsing, seemingly minor changes, like adjusting the encoding, reformatting JSON, or removing whitespace, can alter this sequence. Even if the content’s meaning remains the same, the byte-level data is modified, leading to a different HMAC signature and ultimately causing Signature Verification to fail.