Webhook Signature Verifier
Validate and test HMAC-SHA256 webhook signatures, payloads, and replay defense headers for Stripe, GitHub, Shopify, and Slack.
Webhook Payload & Secret Parameters
Warning: Do not format or pretty-print formatted payload. Exact byte alignment (spaces, tabs, newlines) is critical for HMAC equivalence.
Verification Status & Cryptographic Audit
Enter a received webhook header or click “Fill with computed signature” to execute continuous constant-time equality validation.
Empty
import crypto from "crypto";
export function verifyWebhook(rawBody: Buffer, signatureHeader: string, secret: string): boolean {
const hmac = crypto.createHmac("sha256", secret);
const digest = Buffer.from(hmac.update(rawBody).digest("hex"), "utf8");
const checksum = Buffer.from(signatureHeader, "utf8");
if (checksum.length !== digest.length) return false;
return crypto.timingSafeEqual(digest, checksum);
}Cryptographic Mechanics of Webhook HMAC Signatures
A Webhook is an asynchronous HTTP POST event notification triggered by a service provider (such as Stripe, GitHub, Shopify, or Slack) to inform downstream subscriber services of state transitions. Because webhook receiver URLs are publicly reachable Internet endpoints, relying solely on public access exposes backend systems to forged event payloads, privilege escalation, and Denial of Service (DoS) exploits.
To establish mutual authenticity and payload integrity without the overhead of bilateral public-key infrastructure (PKI), modern web services employ Hash-based Message Authentication Codes (HMAC) standardized under RFC 2104. HMAC utilizes a shared symmetric secret alongside cryptographic hash algorithms, most commonly SHA-256, to produce an authoritative digest across the message body.
Proof of Origin
Only entities possessing the private shared secret key can compute a valid digest. A successful match verifies that the request originates directly from the trusted SaaS vendor.
Tamper Resistance
SHA-256 is mathematically collision-resistant. Modifying even a single whitespace character, JSON number, or boolean in transit results in a totally distinct, non-matching checksum.
Replay Defense
Pre-pending current epoch timestamps to the signed string ensures an eavesdropper cannot capture a valid historical webhook transmission and replay it to drain inventory or issue duplicate credits.
Webhook Verification Architecture by SaaS Provider
Different platforms standardize signature generation headers, canonical formatting schemes, and hashing algorithms differently. Review the architectural specifications across tier-1 service providers:
| Platform | Signature Header | Encoding | Message Construction | Replay Defense |
|---|---|---|---|---|
| Stripe | Stripe-Signature | Hex | t.{timestamp}.{payload} | Built-in (Header t) |
| GitHub | X-Hub-Signature-256 | Hex (sha256=) | {payload} | Via X-GitHub-Delivery ID |
| Shopify | X-Shopify-Hmac-Sha256 | Base64 | {payload} | Via Webhook ID cache |
| Slack | X-Slack-Signature | Hex (v0=) | v0:{timestamp}:{payload} | Built-in (X-Slack-Req-Ts) |
| Svix / Webhooks.com | svix-signature | Base64 (v1,...) | {id}.{timestamp}.{payload} | Built-in (svix-timestamp) |
Why Does My Signature Fail? The Top 4 Debugging Pitfalls
1. Parsing JSON Body Before HMAC Computation
Framework middlewares like express.json() or body-parser parse incoming streams into JavaScript objects. Re-stringifying with JSON.stringify(req.body) disrupts key order, drops empty fields, or normalizes spacing. You MUST preserve the exact raw stream buffer via verify: (req, res, buf) => ... or Next.js route handlers with req.text().
2. Timing Attack Vulnerabilities with ==
Standard string operators abort on the first divergent character. Remote attackers measuring execution latency over thousands of requests can reconstruct byte 0, then byte 1, etc. Always use crypto.timingSafeEqual() in Node.js or hmac.compare_digest() in Python.
3. Line Break Normalization (CRLF vs LF)
Reverse proxies (such as Nginx, Apache, or Cloudflare Workers) can sometimes convert Windows line endings (\r\n) to Unix line breaks (\n). Even a single substituted invisible character will completely break HMAC verification.
4. Production vs Test Secret Mixing
In multi-tenant SaaS environments, webhook secrets differ per webhook endpoint, per application environment, and between CLI local listeners (e.g., stripe listen --forward-to creates a ephemeral secret starting with whsec_ that differs from your Stripe Dashboard endpoint secret).
Frequently Asked Questions (FAQ)
How does HMAC-SHA256 webhook signature verification work?
HMAC (Hash-based Message Authentication Code) combines a cryptographic hash function (SHA-256) with a secret key shared between sender and receiver. The sender calculates the hash over the raw HTTP request payload and attaches it to the request header. The receiving server performs the identical HMAC computation using its shared secret. If the outputs match byte-for-byte in constant time, the payload is authentic and untampered.
Why does signature verification fail when JSON payload looks identical?
HMAC signatures are calculated against the exact raw byte stream of the HTTP body. If your web framework (such as Express, Fastify, Next.js, or Django) automatically parses incoming JSON into an object and re-stringifies it, whitespace differences, line endings (CRLF vs LF), or key ordering will alter the cryptographic hash and fail verification. Webhook endpoints must always consume unparsed raw request bodies.
What is timing-safe equality and why is standard == or === insecure?
Standard string equality operators (== or ===) terminate comparison on the first mismatched character. Attackers can measure the fractional nanosecond differences in server response time to guess valid signature characters sequentially (a side-channel timing attack). Timing-safe equality functions evaluate every byte regardless of whether an early mismatch occurs.
How do webhook timestamp headers mitigate replay attacks?
Providers like Stripe, Slack, and Svix prepend a UNIX timestamp to the signature string. The receiving server verifies that the difference between the current system epoch and the header timestamp falls within an acceptable tolerance window (usually 300 seconds). Any interceptor re-broadcasting an old payload past this window will be rejected.
Does this online HMAC verifier upload my webhook secrets?
No. This tool operates 100% client-side inside your browser sandbox using the W3C Web Cryptography API (crypto.subtle). Your webhook secrets, signatures, and payloads are never transmitted to any external server or backend database.
Related & Complementary Utilities
Explore more privacy-first client-side web tools.
Schema.org FAQPage & Article JSON-LD Microdata Builder
Generate Google-compliant JSON-LD structured data for FAQPage, Article, NewsArticle, and BlogPosting schemas.
XML Sitemap Generator & URL Crawler Suite
Compile Sitemaps.org compliant XML, TXT, and HTML sitemaps for Google Search Console.
HTTP Status Code Reference & Diagnostic Header Matrix
Lookup RFC 9110 HTTP status codes, diagnose API response headers, inspect cURL commands, and test live endpoints in real time.