Verification
Webhook Verification
To ensure that incoming webhook requests are genuinely from Fern and have not been tampered with, you must verify the signature included with each webhook. Fern signs each webhook payload using a secret (the one associated with your subscription) and provides the signature and related information in the request headers. By validating the signature (and checking the timestamp), your application can confirm the authenticity and freshness of the webhook data before processing it.
Signature Headers
Each webhook HTTP request includes the following headers to assist with verification:
x-api-signature
– The HMAC SHA-256 signature of the payload (hex-encoded). This is what you will compare against your own computed signature.x-api-timestamp
– The UNIX timestamp (in seconds or milliseconds) at which the request was sent. This is used in the signature computation and to prevent replay attacks.
Make sure to record the x-api-timestamp
and ensure it is within an acceptable range (for example, within 1 minutes of your server’s current time) before trusting the webhook. If the timestamp is too far out-of-sync, it could indicate a replay attack or an extremely delayed request, and you may want to ignore it. Also, use the payload id
to guard against processing the same event twice.
Signature Generation (TypeScript)
Fern generates the x-api-signature
header by computing an HMAC using SHA-256. The signing string is composed of the timestamp and the request body, separated by a dot. In pseudo-code, Fern does:
The resulting signature is encoded as a hexadecimal string and sent in the header. Important: The exact raw body of the request must be used in this computation. Do not modify the body (even pretty-printing JSON or changing whitespace) before computing the HMAC on your side, as any change will alter the signature.
Here’s an example of how to generate the signature in TypeScript (Node.js environment) using the secret, timestamp, and body:
In this code, we concatenate the timestamp and the body with a period and then create an HMAC using the SHA-256
algorithm with your webhook secret. The output is a hexadecimal string. Fern performs this same computation for each webhook it sends. Your goal in verification is to perform the same computation and compare the result with the signature provided by Fern.
Signature Validation (TypeScript)
To validate a webhook in your handler, follow these steps:
Retrieve the headers and body: Get the
x-api-signature
andx-api-timestamp
from the request headers, and get the raw request body string.Recompute the signature: Use your secret and the received timestamp and body to compute the expected signature (using a function like
generateSignature
above).Compare signatures securely: Check if the computed signature matches the X-Api-Signature from the header. Use a constant-time comparison to avoid timing attacks.
Check timestamp freshness: Verify that the timestamp from
x-api-timestamp
is recent (e.g., within the last few minutes). If it’s too old or far in the future, you may reject the request as a replay attempt.Process the webhook if valid: Only if the signature is valid and the timestamp is acceptable should you proceed to process the webhook (e.g., update your database or trigger other actions). If verification fails, you should reject the request (e.g., respond with 4xx status) or ignore it.
Below is an example implementation in TypeScript for validating the signature of a request:
In the above example, generateSignature
is the function defined in the previous section. We compare the signatures using crypto.timingSafeEqual
which helps prevent timing attacks by making sure the comparison takes the same amount of time regardless of how much of the string matches. We also ensure the buffers are of equal length before comparing (as a safety check).
Last updated