What is HMAC? (Hash-based Message Authentication Code)
HMAC (Hash-based Message Authentication Code) is how two systems prove a message is genuine without sharing anything except a secret key. The sender computes HMAC(secret, message) and attaches the resulting signature; the receiver recomputes it with the same secret. If the two signatures match, the message is authentic and unmodified — no eavesdropper or tamperer in the middle can forge it without the secret.
That one property makes HMAC the workhorse of webhook security. When Razorpay, Stripe or GitHub POSTs an event to your server, the signature in the header is an HMAC of the payload. Your server recomputes it — match means the event really came from them; mismatch means reject it. An HMAC calculator lets you perform that computation by hand while you are building or debugging the integration, instead of guessing why your server keeps saying "invalid signature".
How to generate an HMAC signature
Generating a signature takes three inputs: the message (exactly the bytes being signed — for a webhook, the raw request body), the secret key (the shared secret, never the public key), and the algorithm (usually HMAC-SHA256). This page computes it with the WebCrypto API directly in your browser — the same standardized cryptography your browser uses for HTTPS — and shows the result in hex, base64 and base64url, because different APIs expect different encodings.
The most common mistake at this step is signing the wrong bytes. If you are debugging a webhook and the signature never matches, the odds are overwhelming that your server hashed a parsed-and-reserialized JSON body instead of the raw bytes that arrived over the wire. Whitespace, key order and Unicode escapes all change the bytes, and HMAC signs bytes, not objects. Paste the exact raw payload into the message box here and compare against what your server computed — the difference will show itself.
How to verify an HMAC signature
Verification is generation plus a comparison: recompute the signature for the message and secret you have, then check it against the signature you received. Paste the received signature into the "Verify against" box and this page renders a verdict — green match or red mismatch with the usual suspects listed (wrong secret, altered message bytes, wrong algorithm, hex-vs-base64 confusion).
One honest caveat: this verify mode is a debugging aid, not production security code. In your server, always compare signatures with a constant-time function (crypto.timingSafeEqual in Node, hmac.compare_digest in Python) — a plain === leaks timing information that can theoretically help an attacker guess the signature byte by byte. The browser cannot do much better than string comparison, which is fine for debugging your own integration but not for guarding production traffic.
Webhook signature verification
The pattern is the same across providers: the service signs the raw request body with your webhook secret and puts the signature in a header — X-Razorpay-Signature, Stripe-Signature, X-Hub-Signature-256 for GitHub. Your endpoint recomputes HMAC-SHA256 over the raw body and compares. To debug a failing webhook locally, copy the raw body from your server logs (log it before any JSON parsing), paste it here with your webhook secret, and see whether the output matches the header you received. If it matches here but not on your server, the bug is in how your server reads the body — the classic Express mistake is letting express.json() parse the body before your verification middleware sees the raw bytes.
Razorpay signatures: webhook vs payment
Razorpay has two different signatures, and mixing them up is the single most common Razorpay integration bug. They use different secrets, different messages, and arrive in different places:
- Webhook signature:
HMAC-SHA256(webhook_secret, raw_request_body) → hex, delivered in the X-Razorpay-Signature header. The webhook secret is set in the Razorpay Dashboard where you configure the webhook — it is not your API key secret.
- Payment (checkout) signature:
HMAC-SHA256(key_secret, razorpay_order_id + "|" + razorpay_payment_id) → hex, returned by Checkout as razorpay_signature. This one uses your API key secret.
The preset buttons above configure the tool for each case: the webhook preset sets SHA-256 and reminds you the message must be the raw body; the payment preset fills the order_id|payment_id template so you just replace the two IDs. Both formulas are per Razorpay's documented behavior — if Razorpay ever changes them, their docs are the authority, not this page.
HMAC vs plain hashing
A plain hash like SHA-256 is a fingerprint anyone can compute — it proves a message has not changed since the hash was made, but says nothing about who made it. HMAC folds a secret key into the computation, so a valid HMAC proves two things: the message is unmodified and it came from someone holding the secret. That is why APIs sign with HMAC instead of plain hashes: a hash on a webhook proves nothing, because an attacker can recompute it after modifying the payload. Without the secret, they cannot forge the HMAC.
HMAC algorithms: which one to pick
Always use what your provider specifies — this is not a choice you get to make independently, since both sides must agree. In practice that means HMAC-SHA256 for Razorpay, Stripe, GitHub and most modern APIs. SHA-512 is stronger and fine where supported, but produces longer signatures; SHA-1 is legacy — it survives in old integrations but should not be chosen for anything new. The calculator supports all four so you can match whatever the other side expects.