Skip to main content

What is a webhook signature?

A webhook signature is a webhook security mechanism used to verify the authenticity and integrity of webhook messages sent from a provider to a receiver. It is generated by the provider using a shared secret key and a signing algorithm, most commonly HMAC (Hash-based Message Authentication Code) with SHA-256.

Building webhooks?
Svix is the enterprise ready webhooks sending service. With Svix, you can build a secure, reliable, and scalable webhook platform in minutes. Looking to send webhooks? Give it a try!

How webhook signatures work

When a provider sends a webhook event, it computes the signature by hashing the payload together with the shared secret key. The signature is then included in the webhook request as a header: providers following the Standard Webhooks specification use webhook-signature, while older conventions include X-Signature and GitHub's X-Hub-Signature-256.

Upon receiving the request, the receiver computes the same signature using the same algorithm and its copy of the secret. If the calculated signature matches the one in the header, the receiver can be confident the payload is authentic and wasn't tampered with in transit. Anyone can send an HTTP POST to a webhook endpoint, but only someone holding the secret can produce a valid signature.

A signed request under the Standard Webhooks scheme carries three headers:

webhook-id: msg_2eaf7c9b10
webhook-timestamp: 1753193011
webhook-signature: v1,g0hM9SsE9BqjT8pReExtn4hQoK7oX0dY9lNv2xY6r1o=

The signature is an HMAC-SHA256 hash, which is 256 bits, or 64 hexadecimal characters (base64-encoded in the example above). The v1, prefix is a version tag so the scheme can evolve, and the header can hold multiple space-delimited signatures during a secret rotation. The receiver recomputes the HMAC over the webhook-id, webhook-timestamp, and raw body, and checks it against the header.

Timestamps and replay protection

Well-designed schemes sign a timestamp alongside the payload and reject messages older than a short tolerance window. Without this, an attacker who captures one legitimate request can replay it indefinitely, and each replay carries a perfectly valid signature.

The common default is five minutes: the Standard Webhooks specification recommends a tolerance of 300 seconds, and Stripe's libraries reject events whose timestamp is more than 300 seconds off from server time by default. Because the timestamp is part of the signed content, an attacker can't move it forward without invalidating the signature.

Verifying signatures correctly

Signature verification has a few sharp edges worth knowing.

  • Sign the raw body. The signature must be computed over the raw request body exactly as it arrived. Verifying against a re-serialized version of the parsed JSON fails whenever key order or whitespace differs.
  • Compare in constant time. Use a constant-time comparison function rather than ordinary string equality, since timing differences in early-exit comparisons can leak information about the expected value.
  • Plan for rotation. Secrets need a rotation story, which is why providers send multiple signatures during a rotation window so both the old and new secret verify.

Most webhook providers, including Svix, publish SDKs that handle all of this, and using one is almost always better than hand-rolling verification.

Why signatures instead of other authentication

Signatures are the recommended form of webhook authentication because they fit the shape of the problem. Basic auth and API keys prove who is making a request but say nothing about whether the body was modified in transit; a signature proves both origin and integrity in one check.

MethodProves originProves the body wasn't modifiedResists replay
API key or basic auth in a headerYesNoNo
mTLSYesYes (transport only)No
HMAC signature + timestampYesYesYes

Combined with timestamp verification, signatures protect against spoofing, tampering, and replay attacks in a single check that doesn't depend on the transport.

For more about verifying webhook signatures, check out our full documentation on signature verification and our webhook security best practices.

Frequently asked questions

What algorithm is used to sign webhooks?

Almost always HMAC with SHA-256. The provider hashes the payload (and usually a timestamp) together with a shared secret, producing a 256-bit code sent in a header. Some providers offer asymmetric signing with a public key, but symmetric HMAC-SHA256 is the common default.

Where is the webhook signature sent?

In an HTTP header, not the body. Standard Webhooks uses the webhook-signature header; other providers use names like Stripe-Signature or X-Hub-Signature-256. The receiver reads the header and recomputes the signature over the raw body to compare.

Why does my webhook signature verification fail on a valid request?

The usual cause is verifying against parsed-and-re-serialized JSON instead of the raw request body. Re-serializing changes whitespace and key order, so the bytes differ and the signature no longer matches. Capture the raw body, verify, then parse. A timestamp outside the tolerance window is the other common cause.

How does a signature stop replay attacks?

The signature covers a timestamp as well as the body, and the receiver rejects messages whose timestamp is outside a short tolerance (commonly 5 minutes). An attacker who replays a captured request keeps a valid signature but a stale timestamp, so the receiver drops it.