How to Verify a Webhook Signature
Verify webhook signatures with the exact raw request body, the correct secret, and constant-time comparison so replay and tampering bugs are easier to spot.

Tip
Keep the exact input bytes stable while you test. One changed newline, encoding step, or parser pass can change a hash or signature.
Webhook verification fails most often for boring reasons: the framework parsed the JSON before signing, the wrong secret was loaded, the timestamp window was ignored, or two sides signed slightly different bytes.
The core rule is simple: verify the signature against the exact raw request body and stop if the comparison fails.
The rule that matters
- Read the raw body before JSON parsing changes whitespace or key order.
- Recreate the provider's signing string exactly as documented.
- Use the correct secret for the environment and endpoint.
- Compare signatures with a constant-time helper instead of normal string equality.
Concrete HMAC example
timestamp: 1711641000
payload: {"event":"invoice.paid","id":"evt_123"}
signed: 1711641000.{"event":"invoice.paid","id":"evt_123"}
Many providers then compute an HMAC over that exact byte sequence. Change the newline, pretty-print the JSON, or parse and re-serialize it, and the signature no longer matches.
Packages and libraries worth knowing
- Stripe: use the official SDK and keep the raw request body intact.
- GitHub: verify the
X-Hub-Signature-256header against the raw payload with HMAC-SHA256. - Node.js:
express.raw()or equivalent raw-body middleware is usually the decisive fix. - Python: capture
request.get_data()before parsing and compare withhmac.compare_digest.
Failure case to watch
- Using
req.bodyafter the framework already parsed the JSON. - Mixing the test secret and production secret.
- Verifying only the HMAC and ignoring a timestamp / replay window that the provider expects you to check.
- Logging the shared webhook secret while debugging a mismatch.
Use the verification tools in the right order
- Use Webhook Signature Verify when you have the raw body, secret, and provider header and need the fastest exact-match answer.
- Use HMAC Generator when you need to reproduce the digest step manually and isolate whether the problem is the key, algorithm, or byte sequence.
- Use Secret Redactor before sharing failing headers or payload samples with another person.
What teams ask next
Why does verification fail even when the JSON looks identical?
Because signatures do not care about how the payload looks after parsing. They care about the exact bytes that were signed in transit.
Should I build this myself or use the provider library?
Prefer the provider library when it exists and the behavior is clear. It usually handles the exact header format and replay guidance more reliably than an ad hoc reimplementation.
Developer workflow
Use this guide as an implementation check before you depend on a digest, password hash, or signature in production logic.
- Freeze the exact input bytes, including encoding and newline handling.
- Generate or verify the digest with a small known sample.
- Record the algorithm, comparison rule, and storage format where future maintainers can find it.
1. exact input bytes
2. hash or HMAC operation
3. constant-format comparison
4. document algorithm and encoding