HMAC Generator
Generate HMAC signatures using SHA-256, SHA-512, SHA-384, or SHA-1. Paste your message and secret key, pick an algorithm, and get the hex or Base64 output instantly. Runs entirely in your browser.
All Security ToolsAlgorithm
All output formats
| Format | Value |
|---|
Verify a signature
How this HMAC generator signs messages using the browser’s own crypto engine
HMAC, keyed hash message authentication code, proves two things at once: that a message has not been altered and that whoever produced it knew the secret key. This tool computes real HMAC signatures using the Web Crypto API’s crypto.subtle interface, the same cryptographic engine built into the browser that TLS and WebAuthn rely on. It does not implement its own hash routines in JavaScript, which matters, because a hand-rolled HMAC is exactly the kind of thing that quietly gets the byte handling wrong under edge cases. Everything runs locally. Your key and message never leave the page.
What actually happens on Generate
atob with automatic base64url normalisation.
crypto.subtle.importKey wraps the raw key bytes into a non-extractable CryptoKey object scoped specifically to HMAC with your chosen hash algorithm, restricted to the sign operation only.
TextEncoder, then passed to crypto.subtle.sign('HMAC', cryptoKey, msgBytes), which returns the raw signature as an ArrayBuffer.
The hash function itself, SHA-256 by default with other SHA-2 family options selectable, is not implemented by this tool at all. That work happens inside the browser’s native crypto implementation, which is audited, hardware accelerated where available, and constant time in ways a JavaScript loop cannot reliably guarantee. This is the correct way to do HMAC in a browser: never write your own SHA-256.
Verifying a signature you already have
Paste a candidate signature into the verify field and the tool autodetects whether it looks like hex or Base64, normalises it to lowercase hex, and compares it against the signature it just generated for the current message and key. A match confirms the message, key and algorithm all line up. The comparison itself is a plain string equality check in single threaded JavaScript, not a constant time comparison, which is a reasonable tradeoff for a browser tool checking your own values but not something you should model production verification code after.
| Output format | Character set | Typical use |
|---|---|---|
| Hex | 0 to 9, a to f, lowercase | Debugging, API signature headers, log-friendly |
| Base64 | Standard alphabet with padding | Compact transport in JSON bodies |
| Base64URL | URL-safe alphabet, no padding | Query strings, JWT signature segments |
mysecret as UTF-8 produces a completely different signature than entering those same eight characters interpreted as hex, since hex decoding treats every two characters as one byte. If a signature you are trying to reproduce does not match, check the key encoding dropdown before assuming the key itself is wrong. This trips up more people than any other part of HMAC verification.Two things worth knowing about scope
Key is never marked extractable
The importKey call sets the extractable flag to false, meaning the CryptoKey object cannot be exported back out once created within that call, a minor defensive habit that mirrors how you would build key handling in a real signing service.
All formats table computed once
The Show All Formats panel does not re-sign anything, it just reads the three already-cached encodings of the same signature buffer, so toggling it costs nothing extra in computation.
- RFC 2104 is the original HMAC specification, defining the inner and outer padding construction around a hash function.
- FIPS 198-1 is NIST’s formal standard for the keyed-hash message authentication code.
- W3C Web Cryptography API specifies the
SubtleCryptointerface this tool calls directly, including the HMAC sign and importKey operations. - JWT introduction is useful context since HS256 tokens, the most common JWT signing scheme, are exactly an HMAC-SHA256 signature over a Base64URL encoded header and payload.
Where HMAC is used
Verifying a webhook payload from Stripe, GitHub or similar services that sign requests with a shared secret, debugging why a JWT HS256 signature does not validate, hand checking an API request signature before it ships in production code, and teaching or learning how HMAC actually differs from a plain hash, since a plain SHA-256 of a message plus key is not the same construction and is vulnerable to length extension attacks that HMAC’s nested padding specifically avoids.
Common Questions
Questions About HMAC generator
A regular hash (SHA-256, MD5, etc.) takes a message and produces a fingerprint. Anyone can compute the same hash for the same message. HMAC adds a secret key to that process, so only people who know the key can produce or verify the signature. This makes HMAC suitable for authentication, while plain hashing is only suitable for integrity checking.
The provider (e.g. Stripe, GitHub) computes HMAC-SHA-256 of the raw request body using a shared secret key and sends the result in a header. Your server does the same computation with the same key and compares. If they match, the request is genuine and unmodified. Use this tool to replicate that computation manually when debugging or testing webhooks.
Yes. This tool runs entirely in your browser using the Web Crypto API. Nothing is sent to a server. You can verify this by opening your browser’s network tab before using the tool — no outbound requests are made when you generate. That said, never use production secrets on any third-party website you cannot verify. The fact that this tool is client-side makes it safer than most, but your best option for high-stakes keys is always a local script or your server’s own HMAC library.
It depends on what the receiving system expects. Most API docs specify this explicitly. Stripe uses hex. GitHub webhook signatures use hex with a “sha256=” prefix. JWT uses Base64URL (no padding, URL-safe characters). If you are building something yourself, Base64 is more compact — 44 characters for SHA-256 vs 64 for hex. Base64URL is best for headers and URLs since it avoids special characters.
RFC 2104 recommends keys at least as long as the hash output. For HMAC-SHA-256 that means at least 32 bytes (256 bits). Keys longer than the block size (64 bytes for SHA-256) are hashed first, so there is no benefit beyond 64 bytes. In practice, generate a random 32-64 byte key using a cryptographically secure random number generator and store it securely as an environment variable, not in source code.
SHA-1 is broken for collision resistance — an attacker can craft two different messages with the same hash. But HMAC’s security does not rely on collision resistance; it relies on the hash being a pseudo-random function. HMAC-SHA-1 remains computationally secure against forgery attacks as long as the key is secret. It is still used in OAuth 1.0 and some legacy systems. Avoid it for new work, but it is safe to include for compatibility testing.
From the blog
Security writing without the scare tactics
Practical explanations of hashing, headers, certificates and consent, aimed at people who have to ship something this week.