HMAC Generator
Compute HMAC-SHA1/256/384/512 from a message and secret key. Verify webhook signatures.
How to HMAC Generator Online
Generate an HMAC-SHA1/256/384/512 signature from a message and secret key. Verify against an expected value (webhook authentication).
- Paste the message you want to sign.
- Paste the secret key. Pick the key encoding (UTF-8 if the key is a normal string, hex if it's a hex dump, base64 if it's base64-encoded).
- Pick the algorithm (HMAC-SHA256 is the modern default).
- Pick output encoding: hex (standard for most webhook signatures) or base64.
- Optionally paste an expected HMAC to verify (e.g., the signature from a webhook header).
About HMAC Generator
HMAC is one of those primitives that quietly powers everything. Every webhook from Stripe, Slack, GitHub, PayPal, Discord. Every signed AWS request. JWT's HS256 signing. The session-token format most web frameworks ship. The simple-but-paranoid alternative to TLS in some IoT protocols. It's everywhere, and most developers interact with it without thinking about how it works — until they need to debug a webhook that isn't verifying or generate a test signature for an API integration.
This tool lets you compute HMAC by hand: type a message, type a key, pick the algorithm, get the signature. It uses the browser's **Web Crypto API** (`crypto.subtle.sign` with HMAC), which is the same crypto engine that ships with every modern browser. The implementation is bit-identical to what your server-side Node, Python, Go, or Java HMAC libraries produce for the same inputs. If the tool gives you one value and your server gives you a different value, the inputs don't match — same algorithm, different key encoding, different message bytes, or different output encoding.
**The four algorithms** Web Crypto supports for HMAC:
- **HMAC-SHA1** — legacy. Still used by some older APIs (AWS Signature v2, OAuth 1.0a). Cryptographically the SHA-1 hash function has known weaknesses, but HMAC-SHA1's structure makes those weaknesses much harder to exploit; it's still considered safe for new use cases though not recommended for them. - **HMAC-SHA256** — modern standard. Stripe, GitHub, Slack, AWS Signature v4, JWT's HS256, the vast majority of webhook implementations. The right default. - **HMAC-SHA384** — produces 384-bit signatures. Used when extra-long output is needed for key derivation or when the protocol specifies it. - **HMAC-SHA512** — produces 512-bit signatures. Like SHA-384, mostly used in protocols that explicitly call for it.
For plain message authentication, SHA-256, SHA-384, and SHA-512 are equivalent in practical security. The choice between them is about output size and protocol compatibility. SHA-256 wins on ubiquity.
**The three key encodings** matter because different systems write secret keys differently:
- **UTF-8 string** — the most common case. A secret from a webhook configuration, an environment variable, a copy-paste from an API dashboard. The encoder just calls `TextEncoder.encode` on the input. - **Hex bytes** — when the key is a hex dump (e.g., `a1b2c3d4...` of an even number of hex characters). Common for keys that are random bytes shown to humans in hex form. - **Base64** — when the key is base64-encoded random bytes. Common in JWT contexts and some Slack-style integrations.
If your HMAC isn't matching what the server produces, key encoding is the most common cause. Try each.
**Output encoding** — most APIs use hex (lowercase) for the signature; some use base64. Hex is twice as long as raw bytes but easier to read and case-insensitive-comparable. Base64 is more compact but case-sensitive and includes `+/=` characters that sometimes get URL-encoded weirdly. Pick whichever matches the protocol you're integrating with.
**Verification mode**: the "Compare against expected" field lets you paste a signature from a webhook header or test fixture. The tool normalizes (strips whitespace, lowercases hex) and compares. Match = your message and key reproduce the expected signature, which means the webhook is genuine. No match = something differs (most often: wrong secret, wrong key encoding, message body subtly different from what was signed).
**Common webhook-debugging gotchas**:
- **Trailing newlines.** Some webhook senders sign the raw bytes of the request body, which may or may not have a trailing newline depending on how it was serialized. If your HMAC doesn't match and the message body ends with `\n`, try removing it. - **Whitespace normalization.** JSON pretty-printers re-format the message body. The server signs the exact bytes it sent; if you reformat before computing HMAC, you'll get a different signature. - **Character encoding.** Most HTTP clients send UTF-8 by default but some default to ISO-8859-1 in edge cases. If the message contains non-ASCII characters and your HMAC doesn't match, encoding may be the issue. - **Wrong algorithm version.** Stripe used SHA-256; some older platforms still use SHA-1. The header usually names the algorithm — check.
**Privacy**. The whole tool runs in your browser via Web Crypto. The secret key — the most sensitive input — never leaves your tab. The message is also kept locally. No upload, no server-side computation, no third-party logging. This is the whole point: HMAC tools that send your secret to their server are a non-starter for production work, and there isn't a good reason to do that since browsers have had Web Crypto for a decade.
**Edge cases handled**: hex keys with whitespace (stripped automatically); base64 keys with whitespace (stripped); odd-length hex (clear error); non-hex characters in hex mode (clear error); empty message (no result, no error); empty key (HMAC with zero-length key is valid per spec); HMAC verification with leading/trailing whitespace in the expected value (tolerated, normalized before comparison); hex vs base64 mode switching preserves all other inputs.
Related Tools
Frequently Asked Questions
What is HMAC?
HMAC stands for Hash-based Message Authentication Code. It combines a cryptographic hash (like SHA-256) with a secret key in a specific way so the output proves both the integrity of the message and that whoever produced the output knew the key. It's the mechanism most modern web APIs use for request signing — AWS, Stripe webhooks, Slack webhooks, GitHub webhooks, etc. all use HMAC-SHA256 as their signature primitive.
How is HMAC different from a plain hash?
A plain hash (SHA-256 of a message) doesn't involve a secret, so anyone can compute it. That makes it useful for integrity (catching corruption) but useless for authentication (anyone can compute the hash of any message). HMAC combines the hash with a secret key — without the key you can't produce the right HMAC, even if you have the message and the algorithm. That's what makes it an authentication code instead of just an integrity check.
Which algorithm should I use?
**HMAC-SHA256** for new work. It's what every major web platform uses, the security margin is more than sufficient, and every HMAC library on every platform supports it. Use **HMAC-SHA1** only when an older API specifically requires it (a few legacy systems still do). HMAC-SHA384 and HMAC-SHA512 are useful when you need extra-large output (e.g., for key derivation), but for plain message authentication they're equivalent in security to SHA-256 and produce longer signatures.
Why are there three key-encoding options?
Because different systems describe keys differently. A webhook secret from Stripe is a UTF-8 string. A key from AWS signature v4 is hex-encoded bytes. A JWT-style secret might be base64-encoded random bytes. The crypto library doesn't care about encoding — it works with raw bytes — but you need to tell the tool which encoding the input is in so it can decode to bytes correctly. If your key comes from an environment variable as a printable string, UTF-8 is right. If it's a hex dump, hex. If base64, base64.
Is the secret key sent to a server?
No. The HMAC computation uses the browser's native Web Crypto API (`crypto.subtle.sign` with `HMAC`). The key and message are kept in your tab's memory; the signature is computed locally. Verify in DevTools — paste a key, watch the network panel stay empty. This is critical for keys that authenticate access to real systems; you would not want them flowing through a third-party server.
Can I use this to verify a webhook signature?
Yes. Paste the webhook body as the message, the signing secret as the key (usually UTF-8), pick the algorithm the platform uses (HMAC-SHA256 for most), pick the output encoding the platform uses (hex for Stripe; base64 for some Slack endpoints), then paste the signature from the request header into the 'Compare against expected' box. Match = the webhook is genuine. No match = the body has been tampered with, or you have the wrong secret.
What about HMAC-MD5?
Not exposed by Web Crypto, so not in this tool. MD5 is cryptographically broken (collision attacks exist) but HMAC-MD5 is still considered usable for legacy compatibility because HMAC's construction blunts the attacks. If you need it, the standard JS libraries (`crypto-js`, `noble-hashes`) implement it; we don't include it because adding 50 KB of pure-JS crypto for a deprecated algorithm isn't a great tradeoff.