This guide explains how to validate webhook payloads from Quartr by verifying their cryptographic signatures. We strongly recommend that all consumers implement signature verification to prevent unauthorized or tampered webhook events. In addition to verifying the payload’s signature, you should also validate the timestamp to mitigate replay attacks.
Every webhook event sent by Quartr includes a cryptographic signature in the Webhook-Signature header. Signatures are computed over three elements:webhook-id.webhook-timestamp.payload
webhook-id: A unique message identifier (not user-controlled).
webhook-timestamp: The Unix timestamp (in seconds) at which the message was generated.
If you rotate your webhook secret via the Quartr Dashboard, we will start signing requests with both the old and new secret for 24 hours to allow a seamless transition. During that window:
The Webhook-Signature header will include multiple signatures (e.g., v1,<new_signature> v1,<old_signature>).
You can verify against both secrets. Once you find a match, you can trust the request.
After the rotation window (24 hours), we drop the old secret from the payload entirely. At that point, only the new secret is used, and the old secret should be removed from your verification logic.
Compare the webhook-timestamp header to the current time. If it is too old (e.g., more than 5 minutes or 10 minutes), you should reject it to protect against replay attacks. For example:
js
Copy
Ask AI
const FIVE_MINUTES = 5 * 60; // 5 minutesconst nowInSeconds = Math.floor(Date.now() / 1000);if (nowInSeconds - parseInt(webhookTimestamp, 10) > FIVE_MINUTES) { // The timestamp is too old; reject the request. throw new Error('Webhook timestamp is too old');}
3
Verify the HMAC signature
Split the Webhook-Signature header by spaces, because there may be multiple signatures following a secret rotation. For example, v1,h6Yyyr... v1,XYZ...
Compute the HMAC-SHA256 of signedPayload using your secret. When using the secret one should remove the whsec_ prefix and decode the base64 string. For example:
Compare the result with all the available signatures in the Webhook-Signature header. If any of the available versions match, the payload is authentic and can be trusted.