Webhook Signing Is Not Optional: How to Verify a Callback Without Breaking Your Integration
Every integration eventually gets the same 2 a.m. page: "The webhooks stopped working after the deploy." Nine times out of ten, nothing about the sender changed. What changed was how the receiver verified the signature — a JSON parser that re-serialized the body before hashing, a proxy that added whitespace, a framework upgrade that started decoding the payload before your middleware ran. The…
Webhook signing is crucial to verifying callbacks without breaking your integration. However, many developers encounter issues when the webhooks stop working after a deploy. The problem often lies in how the receiver verifies the signature, which can be affected by JSON parsers that re-serialize the body, proxies that add whitespace, or framework upgrades that decode the payload before middleware runs. This highlights the collision between modern API practice and traditional B2B plumbing.
A webhook signature is an HMAC (usually HMAC-SHA256) computed over the exact raw bytes of the request body, using a shared secret known only to the sender and receiver. It proves two things: authentication, ensuring the payload came from the entity holding the secret, and integrity, ensuring no byte changed during transit. It does not prove the event is fresh or safe to process again, which are separate concerns.
Several common mistakes can break webhook signature verification in production:
1. Hashing the parsed object instead of the raw body. This shifts bytes due to key ordering, unicode escaping, or number formatting, causing the HMAC to fail.
2. Using string equality to compare signatures, which leaks timing information that attackers can exploit to forge valid signatures byte by byte. Use constant-time comparison instead.
3. Ignoring the timestamp, allowing attackers to replay valid requests indefinitely. Verify the signature, then enforce the timestamp tolerance window.
4. Rotating secrets like passwords, using hard-coded or shared secrets without per-partner secrets stored in a secrets manager with rotation windows.
5. Logging the secret or full signature on failure, which exposes the verification secret across multiple systems.
To avoid these issues, follow these steps:
1. Capture the raw body before any parsing or middleware transforms it.
2. Compute the HMAC over the exact bytes received, using the per-partner secret.
3. Use constant-time signature comparison, checking lengths first.
4. Enforce timestamp tolerance, rejecting failures with a 401 and stopping further processing.
5. Deduplicate events based on event IDs or idempotency keys before processing.
6. Persist raw events and return 200 quickly before processing to avoid self-inflicted duplicate problems.
7. Use a secrets manager for per-partner secrets with rotation windows, never logging the secrets or full signatures.
Most webhook bugs are discovered in production, not during unit testing, when real providers send payloads with encoding quirks. A minimal checklist before shipping includes capturing the raw body, computing the HMAC, using constant-time comparison, enforcing timestamp tolerance, deduplicating events, returning 200 quickly, persisting events, and using a staging endpoint to replay captured events and watch verification outcomes. This approach, rooted in EDI practices, ensures secure and reliable webhook integration.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.