🔐 tutorials

Webhook Signature Verification, Explained

By HookNimbus Editorial · Reviewed & edited by Franklin Brown ·July 4, 2026

Why Sign a Webhook at All?

Your webhook endpoint is a public URL. Anyone who discovers it can send it a request that looks exactly like a real event - a fake “payment succeeded,” a spoofed “order placed.” Signature verification is how you tell a genuine provider request from a forgery. The provider computes a cryptographic signature of the payload using a secret only the two of you share, and sends that signature in a header. You recompute it and compare. A match proves two things at once: the request came from someone holding the secret, and the body was not modified in transit.

How HMAC Signatures Work

Most providers use HMAC-SHA256: a keyed hash of the raw request body using your signing secret as the key. The output is a fixed-length digest, usually shown as hex. Because the digest depends on both the secret and every byte of the body, changing either one changes the result completely - and an attacker who does not know the secret cannot produce a valid digest.

Verification is symmetric: you run the same HMAC over the body you received with your copy of the secret, and check that your digest equals the one in the header. Always compare using a constant-time comparison so timing does not leak information.

The Mistake That Breaks Almost Every Failed Check

Here is the single most common cause of a signature that will not match:

You verified against a re-serialized body instead of the raw bytes you received.

If your framework parses the JSON body before your handler runs, then you re-JSON.stringify it to verify, the whitespace and key order will differ from what the provider signed - and the HMAC will not match, even though nothing is wrong with the secret. Always verify against the exact raw body, the same bytes the provider hashed. In Express, read the raw body with a buffer; in most edge runtimes, call await request.text() before anything parses it.

Provider Specifics

Verify It Without Deploying

You do not need to push code to test a signature. Capture the exact raw body with the Webhook Inspector, then paste the body, your secret, and the signature header into the Signature Verifier. It computes the expected signature in your browser (your secret never leaves the page) and tells you whether it matches - and if it does not, you will immediately know whether to suspect the secret or your body handling.

Checklist

  1. Read the raw body before parsing.
  2. Use the provider’s exact scheme (GitHub hex, Stripe timestamped, Shopify base64).
  3. Compare in constant time.
  4. For Stripe, reject stale timestamps to stop replay attacks.
  5. Never log the signing secret.

Get these right and forged requests bounce off your endpoint while real ones sail through.

Try the tools from this article

Our articles are drafted with AI assistance and reviewed, fact-checked, and edited by a human editor before publishing.