Skip to content

Webhook signature

Definition

A webhook signature proves a request really came from the service and not from somebody who found your URL. The sender computes a keyed hash over the exact bytes it is about to send, using a secret only the two of you hold, and puts it in a header. You compute the same hash and compare. Check the timestamp too, or a captured request can be replayed at you.

At a glance

Category
Security
Built on
HMAC over the raw request body and a timestamp
Travels in
Headers carrying the identifier, the timestamp and the signature
Verify against
The raw bytes, before any JSON parsing
Compare with
A constant-time comparison
Also check
That the timestamp is recent, to refuse replays

How it works

The service takes the timestamp and the exact body bytes, computes a keyed hash with the secret belonging to that endpoint, and sends the result in a header alongside the timestamp and a delivery identifier. Your handler reads the body as raw bytes, recomputes the hash with the same secret and compares the two in constant time. It then checks that the timestamp is within a small window of now, and refuses the request if it is not, which is what makes a captured delivery useless later.

Why it matters

Your endpoint is a public URL, so without verification the only thing separating a real event from an invented one is knowing the shape of the JSON, which is not a secret. An attacker who can post to it can mark a message delivered, suppress an address or corrupt whatever the handler writes. Verification turns the endpoint into something only the service can write to, and the timestamp check turns a single captured request into something that expires. Both halves are needed: a signature without a window is replayable, and a window without a signature protects nothing at all.

Example

A handler reads the request body as bytes before parsing anything. It recomputes the signature with the endpoint's secret and compares it with the header using a constant-time function. It then confirms the timestamp is within a few minutes of now. Only then does it parse the JSON and queue the event. A replayed delivery captured yesterday fails the timestamp check and is refused with no side effects.

Common mistakes

  1. 01Verifying against a re-serialised body, so a difference in key order or spacing breaks every signature for no reason.
  2. 02Comparing signatures with an ordinary equality operator, which leaks timing information an attacker can exploit.
  3. 03Skipping the timestamp check, which leaves any captured request replayable indefinitely.
  4. 04Logging the signing secret or the raw header during debugging, which puts both halves of the scheme in your log store.

In Rasket

Every delivery carries svix-id, svix-timestamp and svix-signature headers, and a published helper verifies them for you. Webhooks

Frequently asked questions

Why must I use the raw body?

Because the signature is computed over exact bytes. Parsing JSON and serialising it again can change whitespace, key order or number formatting, and any of those produces a different hash.

What timestamp window should I allow?

A few minutes is the usual choice, wide enough for clock skew and network delay but narrow enough that a captured request stops working quickly. Reject anything outside it rather than warning.

What if my secret leaks?

Rotate it, and treat every delivery verified with the old secret as untrusted from the moment of the leak. Keeping a distinct secret per endpoint limits how much a single leak affects.

Last updated 16 September 2026.

Start sending this morning

Verify a domain and send your first email in minutes.