How Hash-Based Message Authentication Codes (HMAC) Work
When the provider sends a webhook, they compute a cryptographic hash of the raw HTTP request body combined with a shared secret key using HMAC-SHA256. This signature is placed in a custom header (e.g. Stripe-Signature or X-Hub-Signature-256).
Your server receives the payload, computes the identical HMAC locally with your secret, and compares the two hashes. If they match, the payload is authentic and was not altered in transit.
The Danger of String Equality: Timing Attacks
Comparing signatures using standard string comparison (signature === expected) is vulnerable to side-channel timing attacks. Standard comparisons return false on the first mismatched byte, allowing attackers to measure microsecond response variations to brute-force valid signatures.
Always use constant-time comparison algorithms like Node.js crypto.timingSafeEqual().
Step-by-Step Tutorial
Input Raw Webhook Payload
Paste the raw, unparsed JSON payload exactly as received in the HTTP body.
Provide Secret Key & Received Header
Enter your webhook signing secret and the signature header provided by the service.
Verify Cryptographic Authenticity
DocSwift computes the HMAC-SHA256 hash locally in your browser to verify integrity.
Ready to Try It Yourself?
DocSwift processes everything directly on your device. Fast, safe, and completely free forever.
How helpful was this guide?
Rated 4.9 / 5 by 3,420+ users worldwide
Share with Colleagues & Friends
Help others protect their document privacy
Frequently Asked Questions
Why does JSON.stringify(req.body) cause HMAC verification to fail?
JSON parsers do not guarantee deterministic key order and strip whitespace. Cryptographic hashing is bit-exact: any altered character produces a completely different hash.
How do webhook providers prevent replay attacks?
Providers like Stripe include a timestamp in the signature header (t=...). Servers must verify that the timestamp is within a 5-minute tolerance of the current system clock.