HMAC generator — SHA-256, SHA-384 and SHA-512
A HMAC (Hash-based Message Authentication Code, RFC 2104) combines a secret key with your message to produce a keyed hash. Anyone who knows the key can recompute the same value, which proves the message was not tampered with and came from someone holding the key. It is the standard way to sign API requests and verify webhook payloads.
How it works
The tool uses the browser’s Web Crypto API. It UTF-8 encodes your secret key
and imports it as an HMAC key bound to the chosen hash (SHA-256, SHA-384 or
SHA-512), UTF-8 encodes your message, then calls crypto.subtle.sign to produce
the authentication code. The resulting bytes are rendered as a lowercase hex
string. Internally HMAC hashes the key combined with the message twice with inner
and outer padding, which is what makes it resistant to length-extension attacks
that affect a naive key-plus-message hash. The output updates live as you type.
Example
With key topsecret and message hello, HMAC-SHA-256 produces a fixed 64-character
hex string. Re-running with the same inputs always gives the same value; changing
a single character of either input changes the entire output.
| Algorithm | Output bits | Hex length |
|---|---|---|
| HMAC-SHA-256 | 256 | 64 |
| HMAC-SHA-384 | 384 | 96 |
| HMAC-SHA-512 | 512 | 128 |
Everything runs locally in your browser via the Web Crypto API — your key and payload are never sent over the network.
Step-by-step: verifying a Stripe webhook
Webhook signature verification is one of the most common real-world uses for HMAC. Here is how the process works for Stripe as a concrete example:
- Stripe sends a POST request to your endpoint with a
Stripe-Signatureheader that looks liket=1234567890,v1=abc123.... - The
t=value is the timestamp Stripe signed. Thev1=value is the HMAC-SHA-256 of the stringtimestamp + "." + raw_body, signed with your webhook endpoint’s signing secret. - To verify: take the signing secret from your Stripe dashboard as the key, construct the signed payload as
timestamp + "." + rawBody, compute HMAC-SHA-256, and compare to thev1=value in the header.
This tool is helpful for testing that verification manually: paste the signing secret as the key and the constructed payload string as the message, then compare the hex output to what Stripe sent. If they match, the payload is authentic.
GitHub, Slack, and most other platforms follow the same pattern with minor variations in how they format the signature header.
Why HMAC is better than a plain hash for this job
A plain SHA-256 of the message alone would let an attacker compute any signature themselves (without the key), rendering it useless for authentication. HMAC addresses this by mixing the key into the hash in a structured way.
Beyond that, HMAC is specifically resistant to length-extension attacks — a class of attack that affects SHA-256 when used naively as SHA256(key || message). The inner-and-outer padding structure of HMAC prevents an attacker from appending data to a signed message and computing a new valid signature without knowing the key.
Encoding tips: getting the inputs right
HMAC is deterministic, which means the inputs must match exactly. Two common sources of mismatch:
- Trailing newlines — many terminals and editors add a
\nat the end of copied text. If your computed HMAC does not match, check whether either input has an extra newline. - Hex vs. raw bytes for the key — some platforms (for example some JWT libraries) provide the secret as a base64 or hex string that must be decoded to raw bytes before use. This tool treats both key and message as UTF-8 text; if your secret is base64-encoded, decode it first.