Webhook Signature
Webhook Signing Mechanism
To ensure the authenticity and integrity of webhook calls, Zyphe uses a signing mechanism based on HMAC (Hash-based Message Authentication Code) with SHA256. This allows you to verify that the webhook payload has not been tampered with and genuinely originates from the Zyphe platform.
How it Works
- Secret Key: Each organization is assigned a unique secret key. This key is crucial for both signing and verifying the webhook payloads. Keep this secret key confidential.
- Timestamp: A Unix timestamp (number of seconds since the Unix epoch, UTC) is generated at the time the webhook is sent.
- Signed Payload Construction: The raw JSON payload of the webhook request is combined with the timestamp. Specifically, the timestamp is prepended to the payload, separated by a
.(dot).
signed_payload = "{timestamp}.{raw_json_payload}"
For example, if the timestamp is 1678886400 and the raw payload is {"event":"user.created", "data":{"id":"123"}}, the signed_payload string that will be signed will be:
1678886400.{"event":"user.created", "data":{"id":"123"}}
HMAC Generation:
- The secret key (provided as a hexadecimal string) is first decoded into its raw byte representation.
- An HMAC-SHA256 algorithm is initialized using this decoded secret key.
- The raw bytes of the
signed_payload(including the timestamp and the dot separator) are then fed into the HMAC algorithm. - The HMAC algorithm computes a unique message authentication code based on the secret key and the combined
signed_payload.
- Signature Header: The resulting HMAC value is then encoded into a hexadecimal string and included in the webhook request's
x-signatureheader. The signature header also include the timestamp and is formatted the following way:
t=<timestamp>.v0=<signature_hex>
Verifying Webhook Signatures
When your application receives a webhook, you should perform the following steps to verify its signature:
-
Retrieve Headers:
- Get the signature value from the
x-signatureheader. - Extract the timestamp and the actual signature hex from the x-signature header
- Get the signature value from the
-
Retrieve the Payload: Obtain the raw, unmodified body of the webhook request. It is critical to use the exact raw body received, without any parsing or re-serialization, as even subtle changes can cause the signature verification to fail.
-
Construct the Signed Payload: Combine the retrieved timestamp and the raw webhook payload in the exact same format used by Zyphe:
local_signed_payload = "{received_timestamp}.{raw_request_body}" -
Calculate Your Own Signature: Using your organization's secret key and the
local_signed_payloadconstructed in the previous step, compute an HMAC-SHA256 signature locally, following the same steps described in the "HMAC Generation" section above. -
Compare Signatures: Compare your computed signature (hexadecimal string) with the signature received in the
x-signatureheader.- If they match, you can be confident that the webhook is authentic and untampered.
- If they do not match, do not process the webhook, as it may be fraudulent or corrupted.
-
Timestamp Verification (Recommended for Replay Attack Mitigation): As an additional security measure, you should verify the timestamp to mitigate replay attacks:
- Parse the timestamp collected from the
x-signatureheader as an integer representing seconds since the Unix epoch. - Compare this timestamp with your server's current UTC time.
- Reject webhooks where the timestamp is significantly older (e.g., more than 5 minutes) or significantly in the future. This ensures that old, intercepted webhooks cannot be replayed successfully.
- Parse the timestamp collected from the