HMAC Generator
Compute HMAC-SHA256, SHA-1, SHA-384 or SHA-512 of text, hex or Base64 with any key, verify a signature, and rebuild GitHub, Stripe and Slack webhook signatures.
The interactive tool loads here when JavaScript runs.
About this toolWhat is the HMAC Generator?
Enter a secret key and a message, and this generator returns the HMAC in hex, Base64 and Base64url at once, using SHA-256, SHA-1, SHA-384 or SHA-512. Keys and messages can be plain UTF-8 text, hex or Base64, so you can reproduce a signature whatever form the secret was handed to you in. Paste a signature you received and the tool checks it with a constant-time comparison, accepting hex or Base64 and prefixes such as sha256= or v0=.
Most people reach for an HMAC tool while debugging a webhook. Three recipes are built in. GitHub signs the raw body and sends X-Hub-Signature-256: sha256=<hex>. Stripe signs "timestamp.body" and sends t= and v1= in the Stripe-Signature header. Slack signs "v0:timestamp:body" and sends X-Slack-Signature: v0=<hex>. Pick one, paste the body and secret, and the tool shows the exact string that was signed and the header your endpoint should have received.
The computation uses the browser's Web Crypto API. Keys and messages are not uploaded.
- HMAC-SHA256, SHA-1, SHA-384 and SHA-512 with Web Crypto
- Text, hex or Base64 keys and messages
- Hex, Base64 and Base64url output side by side
- Constant-time signature check that accepts prefixed values
- GitHub, Stripe and Slack webhook recipes with the exact header
- Random 256-bit key generator
- Verified against RFC 4231 and RFC 2202 test vectors
How to use the HMAC Generator
- Choose a recipe: Plain message, or the GitHub, Stripe or Slack webhook format.
- Pick the hash function (webhook recipes always use SHA-256).
- Enter the secret key and say whether it is text, hex or Base64. Use Random for a new 256-bit key.
- Paste the message or raw request body. For Stripe and Slack, also enter the timestamp from the request headers.
- Copy the HMAC in the format you need, or paste a received signature into the verify box to see whether it matches.
Worked examples
The Wikipedia example
Input
Key "key", message "The quick brown fox jumps over the lazy dog", HMAC-SHA256
Output
f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8
A well-known reference value that is handy for checking an implementation in another language.
RFC 4231 test case 2
Input
Key "Jefe", message "what do ya want for nothing?", HMAC-SHA256
Output
5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843
One of the official vectors the tool is tested against, alongside the SHA-384 and SHA-512 results for the same input.
Stripe webhook
Input
Secret whsec_..., timestamp 1700000000, body {"ok":true}Output
Signed string 1700000000.{"ok":true}, header Stripe-Signature: t=1700000000,v1=<hex>If your computed v1 differs from Stripe's, the body was almost certainly modified before verification, for example by a JSON body parser.
Background and insight
HMAC is defined in RFC 2104 (1997) and FIPS 198-1: HMAC(K, m) = H((K′ ⊕ opad) ‖ H((K′ ⊕ ipad) ‖ m)), where K′ is the key padded to the hash block size (64 bytes for SHA-1 and SHA-256, 128 bytes for SHA-384 and SHA-512), or hashed first if it is longer, and ipad and opad are the bytes 0x36 and 0x5c repeated. The nested structure is what stops the length-extension attack that breaks a naive H(key ‖ message) construction with SHA-256.
Security depends on the key. RFC 2104 recommends a key at least as long as the hash output, so 32 random bytes for HMAC-SHA256. HMAC-SHA1 remains secure as a MAC even though SHA-1 collisions are practical, because HMAC does not rely on collision resistance; new systems still use SHA-256. The correctness of this tool is checked against the test vectors in RFC 4231 (HMAC-SHA224 to SHA512) and RFC 2202 (HMAC-SHA1).
Verifying a signature has two traps. First, the bytes must be identical: a webhook body that was parsed and re-serialised as JSON, or had its line endings changed, will not verify. Second, the comparison should take the same time whether the first or last byte differs, otherwise an attacker can learn the signature byte by byte. Use crypto.timingSafeEqual in Node, hmac.compare_digest in Python, hash_equals in PHP or MessageDigest.isEqual in Java.
Common use cases
Debugging webhook verification
Reproduce the signature GitHub, Stripe or Slack sent and find out whether the key, the body or the timestamp is wrong.
Signing API requests
Check the signature your client computes for an HMAC-authenticated API against an independent implementation.
Generating test fixtures
Create known HMAC values in hex or Base64 for unit tests in any language.
Checking HS256 JWT secrets
Compute HMAC-SHA256 over header.payload and compare it with a token's signature in Base64url.
Tips and limitations
- Sign and verify the raw bytes. In Express use express.raw() on the webhook route; in other frameworks read the body before any JSON parsing.
- Make sure both sides use the same key encoding. A hex string used as UTF-8 text is a different key from the bytes it represents.
- Reject webhook timestamps older than a few minutes (Stripe and Slack suggest five) to stop replayed requests.
- Use at least 32 random bytes as an HMAC-SHA256 key. A short human-chosen password as the key can be brute forced offline from one signed message.
- HMAC proves who sent a message and that it was not changed. It does not hide the contents; encrypt separately if they are secret.
Frequently asked questions
What is the difference between HMAC and a plain hash?
A hash such as SHA-256 has no key, so anyone can compute it, and it only detects accidental changes. An HMAC mixes in a secret key, so only someone holding the key can produce a valid value, which proves the message came from them and was not altered.
Should I output HMAC in hex or Base64?
Either; they encode the same bytes. Hex is 64 characters for SHA-256 and is what GitHub, Stripe and Slack use. Base64 is 44 characters and is common in HTTP headers and AWS-style signatures. Base64url without padding is used in JWTs.
Why does my GitHub webhook signature not match?
Usually the body was parsed and re-serialised before hashing, or the secret has a trailing newline or space. Compute over the raw request bytes with the exact secret configured in the repository settings, and compare with X-Hub-Signature-256, not the older SHA-1 header.
How long should an HMAC key be?
RFC 2104 recommends at least the hash output length: 32 bytes for SHA-256, 64 for SHA-512. Longer keys are allowed but are hashed down to the output length first if they exceed the block size, so they add nothing.
Is HMAC-SHA1 still secure?
For message authentication, yes. Known SHA-1 attacks find collisions, which HMAC does not depend on. It is still sensible to use HMAC-SHA256 for anything new and to accept SHA-1 only where a protocol requires it.
Can HMAC be reversed to recover the message or key?
No. Like the hash inside it, HMAC is one-way. The only attack on a properly random key is brute force, which is infeasible for 128 bits or more. Weak, guessable keys can be found by trying candidates against a known message and signature.
Is there an in-depth guide to the HMAC Generator?
Yes. “HMAC Signatures Explained, with GitHub, Stripe and Slack Webhooks” covers the background, how it works, common pitfalls and worked examples. Read the full guide.
People also search for
- hmac sha256 online with secret key
- verify github webhook signature x-hub-signature-256
- stripe webhook signature mismatch
- slack signing secret verify request
- hmac sha256 base64 vs hex output
- difference between hmac and hash
- how to compute hmac in javascript web crypto
- hmac key length recommendation
Related Tools You May Like
Free, in-browser tools that pair well with this one.