HMAC Generator
A message and a secret key, hashed together — for verifying a signature, not just checking a checksum.
Message
HMAC
Type a message and a secret key to see the HMAC here.
A hash proves nothing without a shared secret — that is what HMAC adds
A plain hash — the kind Hash Generator computes — proves a message was not altered, but anyone can compute it, including whoever tampered with the message. HMAC (Hash-based Message Authentication Code) fixes that by mixing a secret key into the hash, so the resulting code can only be reproduced by someone who also holds the key. That is the mechanism behind "signing" a webhook payload or an API request: the sender computes an HMAC with a shared secret, the receiver recomputes it on their end, and a mismatch means either the message changed in transit or the sender did not actually know the secret.
This page computes HMAC-SHA1, HMAC-SHA256, HMAC-SHA384 and HMAC-SHA512 at once, all through the browser's own SubtleCrypto.sign() with an HMAC key imported via importKey — the platform's real, audited implementation of RFC 2104, not a hand-rolled ipad/opad construction. There is no HMAC-MD5 here for the same reason there is no bare MD5-family shortcut elsewhere on this site's crypto tools: the Web Crypto API never added MD5, and reimplementing its key schedule by hand is exactly the kind of code this page exists to avoid writing.
The secret key can be read three ways — as plain text, as hex digits, or as Base64 — because a real key rarely arrives as one consistent shape. A webhook secret from a dashboard is usually plain text; a key derived from a certificate or another cryptographic operation often comes as hex or Base64. Decoding a hex or Base64 key as if it were literal UTF-8 text is the single most common reason someone's recomputed HMAC does not match the sender's — the bytes are simply different from what was intended.
Everything runs in your browser. The secret key you paste here — the entire point of which is that it stays secret — is never sent anywhere.
Computing an HMAC
- Paste the message – The exact bytes that were signed — for a webhook, this is usually the raw request body, not a reformatted or re-indented copy of it.
- Enter the secret key and its encoding – Match the encoding the sender actually used. A key that looks like hex or Base64 almost always is one — treating it as plain text produces a completely different HMAC.
- Compare against the signature you received – Most services put their signature in a header (
X-Hub-Signature-256,Stripe-Signature) as hex or Base64 — match the output encoding here to what they sent.
A trailing newline breaks the comparison just as often here as with a plain hash. If your recomputed HMAC does not match a webhook provider's signature and the message text looks identical, check whether you re-serialized the JSON body (which can reorder keys or change whitespace) instead of using the exact raw bytes the provider sent — HMAC is byte-exact, and a cosmetically identical payload with different whitespace produces a completely different code.
The same message, keyed two different ways
The message "The quick brown fox jumps over the lazy dog" with the plain-text key "secret" — short enough to try in a terminal and compare (echo -n "..." | openssl dgst -sha256 -hmac "secret").
message: The quick brown fox jumps over the lazy dog key: secret
54cd5b827c0ec938fa072a29b177469c843317b095591dc846767aa338bac600
When you need this
Verifying a webhook signature
GitHub, Stripe, Shopify and most other webhook senders sign the request body with a shared secret and put the result in a header. Recomputing the HMAC here against the raw payload and secret confirms whether a webhook handler you are debugging is verifying correctly, without adding logging to production code.
Signing an API request by hand while debugging
Some APIs (AWS SigV4-style schemes, older exchange APIs) require a per-request HMAC signature built from specific fields. Computing one candidate here and comparing it against what your code produces isolates whether a signing bug is in the message construction or the key.
Checking two systems agree on a shared secret
If two services that are supposed to share an HMAC secret disagree on it, every signed request between them fails. Computing the same HMAC independently on both ends against a known test message is a fast way to confirm the secret itself, not the surrounding code, is the mismatch.
Generating a tamper-evident token
A short-lived value plus an HMAC of it, verified server-side against the same secret, is a common lightweight way to prove a token was issued by you and has not been altered — without the overhead of a full signing certificate.
What this page does
- Computes HMAC-SHA1, HMAC-SHA256, HMAC-SHA384 and HMAC-SHA512 simultaneously from one message and key.
- Reads the secret key as plain text, hex, or Base64 — matching however the key actually arrived.
- Shows the result as hex or Base64, matching whichever a webhook provider or API put in its signature header.
- Uses the browser's own
SubtleCryptoHMAC implementation — the platform's real code, not a reimplementation. - Runs entirely in your browser — the secret key is never sent anywhere.
Questions people actually ask
What is the difference between this and Hash Generator?
Hash Generator computes a hash of the message alone — anyone can reproduce it, which makes it good for catching accidental corruption but useless for proving who sent something. HMAC mixes in a secret key, so only someone who also knows the key can produce a matching code, which is what makes it usable for verifying a signature.
Why is there no HMAC-MD5?
The Web Crypto API this page is built on never implemented MD5 in the first place — it was left out of the specification because MD5 is broken for anything security-sensitive. Building HMAC-MD5 would mean hand-rolling MD5's key schedule, which is exactly the kind of code this page avoids writing by using the browser's real, audited HMAC implementation.
My computed HMAC does not match — what usually causes that?
In order of how often it actually turns out to be the cause: the key encoding is wrong (a hex or Base64 key read as plain text); the message has been re-serialized or re-whitespaced instead of using the exact original bytes; or the output encoding does not match what you are comparing against (hex versus Base64).
Can I use this for password storage?
No — HMAC (like a plain hash) is fast to compute, which is the wrong property for password storage, where slowness against brute-force guessing is the point. Use a purpose-built password hash like bcrypt or Argon2 instead.
Related tools
Specifications and references
- RFC 2104 — HMAC: Keyed-Hashing for Message Authentication – The specification this page implements, via the browser's own HMAC support
- MDN — SubtleCrypto.sign() – The Web Crypto API method behind this page's HMAC computation