How to Authenticate Webhook Payloads
Welcome to the documentation for how to authenticate webhook payloads sent from Reflex. This feature allows you to securely receive webhook events by validating requests using a webhook secret.
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.
Reflex Dashboard
GraphQL API
Please note that the Reflex GraphQL API is available at https://reflex.amboss.tech/graphql .
query Team {
getUser {
team {
webhook_secret
}
}
}
Example Response
{
"data": {
"getUser": {
"team": {
"webhook_secret": "0ed52732-3e29-4f51-ba46-5ef0fb06b893"
}
}
}
}
Validating Webhook Requests
To verify the authenticity of incoming webhooks:
- Ensure that the
Amboss-Secret
header is present in the request and retrieve it. - Compute an
HMAC-SHA256
hash of the request payload using yourwebhook_secret
. - Compare the computed hash with the
Amboss-Secret
header value sent by Reflex.
How to Compute the Hash
Example in JavaScript
const crypto = require("crypto");
function computeHash(payload, webhook_secret) {
const hash = crypto
.createHmac("sha256", webhook_secret)
.update(Buffer.from(JSON.stringify(payload), "utf8"))
.digest("hex")
.toLowerCase();
return hash;
}
Example in Python
hash_val = hmac \
.new(
api_key.encode('utf-8'),
msg=bytes(payload, encoding='utf-8'),
digestmod=hashlib.sha256
) \
.hexdigest() \
.lower()
print(hash_val)
This example function verifyWebhook()
performs the following tasks:
- Generating an
HMAC-SHA256
hash of the received payload using yourwebhook_secret
. - Encoding the payload consistently by converting it into a
UTF-8
JSON string before hashing. - It returns the final hash.
- After this, we can compare the obtained hash with the received
Amboss-Secret
header value.
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.
Amboss Secret Header
0ed52732-3e29-4f51-ba46-5ef0fb06b893
Webhook Payload
const payload = {
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
7a1b3851371c4ad8d1218ee3a2f69a64752ad48aafb0360544428c1c16551a16
Checks
- This computed hash should be compared with the value of the
Amboss-Secret
header. - If both of the values matches, 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.