Verify Webhooks - Flex Documentation
Verifying signatures
Each webhook call includes three headers with additional information that are used for verification:
- svix-id: This is the unique message identifier for the webhook message. This identifier is unique across all messages but will be the same when the same webhook is being resent (e.g. due to a previous failure).
- svix-timestamp: This indicates when the webhook was sent. It's also unique to each webhook, repeating only under the same webhook message being resent.
- svix-signature: This is the Base64 encoded list of signatures (space delimited). Each signature is prefixed with a version (e.g.,
v1,). When comparing signatures, you should strip this prefix and compare only the signature portion after the comma.
The content to sign is composed by concatenating the id, timestamp, and payload, separated by the full-stop character. Flex uses an HMAC with SHA-256 to sign its webhooks. To calculate the expected signature, you should HMAC the signed_content from above using the base64 portion of your signing secret (this is the part after the whsec_ prefix).
For example, given the secret fwhsec_Y2NhZDczMDYtNDEyYi0xMWVlLTg5MTItNGY4Y2E5ZmU1MmI4, you will want to use Y2NhZDczMDYtNDEyYi0xMWVlLTg5MTItNGY4Y2E5ZmU1MmI4.
Here is an example of calculating the signature:
const crypto = require("crypto");
signedContent = `${flex_event_id}.${flex_timestamp}.${body}`;
const secret = "fwhsec_Y2NhZDczMDYtNDEyYi0xMWVlLTg5MTItNGY4Y2E5ZmU1MmI4";
// Need to base64 decode the secret
const secretBytes = Buffer.from(secret.split("_")[1], "base64");
const signature = crypto
.createHmac("sha256", secretBytes)
.update(signedContent)
.digest("base64");
console.log(signature);
signature should match the contents of svix-signature specified in the header.