Security / LOCAL TOOL

HMAC Generator & Verifier

Compute and verify HMAC-SHA256, SHA-384, and SHA-512 signatures locally. Your payload and secret never leave the browser.

Runs locally — input is never uploaded
Paste the signed payload
Required
Ready when you are
Optional, to verify

WHAT IT DOES

Check a webhook signature without pasting your secret into someone's server.

Enter the exact payload that was signed and the shared secret, and the HMAC is computed in your browser with the Web Crypto API. Output is hex or base64, whichever your provider uses. Paste the signature you received into the expected field and the two are compared byte by byte, so a base64 signature verifies against a hex computation without you having to convert anything first. This is the check that fails when a webhook is rejected, and doing it on a page that transmits neither the payload nor the secret means you can run it against real production values.

Why use it?

Use it to reproduce a webhook signature calculation and isolate whether the disagreement is in the payload bytes, secret, hash algorithm, or signature encoding.

How to use this tool

  1. Paste the exact signed payload, enter the shared secret, and choose the sender's hash algorithm and output encoding.
  2. If comparing a received signature, paste it into the expected field and generate. Leaving that field empty means verification is not checked.
  3. Do not pretty-print JSON before checking it: whitespace and trailing newlines change the signed bytes. If a provider signs a timestamp plus the body, assemble that exact input first; accepting a signature header does not reconstruct the provider's signing procedure.

Details and limitations

  • Signing uses the Web Crypto API's HMAC implementation, so the result matches what any correct server-side library produces for the same payload, secret, and hash.
  • Verification is optional and reports one of three outcomes: verified, does not match, or not checked. An unchecked signature is never presented as a passing one.
  • Common signature headers are understood directly. A GitHub sha256=... value, a Stripe v1=... element, and a bare base64 digest are all accepted, so a header can be pasted as received.
  • The expected MAC is decoded to bytes before comparison, so hex and base64 forms of the same signature verify against each other.
  • The comparison runs in time independent of where the first differing byte falls, which is the property a server needs even though this page has nothing remote to leak it to.

COMMON QUESTIONS

HMAC questions

Why does my webhook signature not match?
Almost always because the payload differs by a byte from what was signed. Sign the raw request body exactly as received, before any JSON parsing and re-serialisation, which reorders keys and changes whitespace. Check too that you are using the endpoint's own signing secret rather than an API key, and the hash your provider documents.
Can I paste the signature header exactly as I received it?
Yes. A leading sha256=, sha1=, or v1= label is recognised and stripped, and a Stripe-style comma-separated header has its v1 element picked out. Hex and base64 are both accepted, and the comparison decodes to bytes first, so the encoding you paste does not have to match the encoding shown.
Is HMAC-SHA256 still considered secure?
Yes. HMAC's security does not rest on the hash being collision resistant, which is why HMAC-SHA1 remained sound long after SHA-1 collisions were demonstrated. HMAC-SHA256 is the standard choice for webhook and API request signing today.
Why does the comparison need to be constant time?
On a server it does. A comparison that returns as soon as two bytes differ takes measurably longer the more leading bytes are correct, which lets an attacker who can send repeated requests recover a valid signature one byte at a time. This page compares in constant time as well, though it gains nothing from it here: both values are already on your machine and there is no remote observer to time it.