HMAC Generator — Create HMAC Signatures Online

Generate HMAC (Hash-based Message Authentication Code) signatures using SHA-256, SHA-384, or SHA-512. Enter your message and secret key to produce a secure authentication tag for API signing and webhook verification. 100% client-side — nothing is sent to any server.

HMAC Generator


HMAC Signature Enter message and secret key

What is an HMAC? An HMAC is a fixed-length authentication tag computed from a message and a shared secret key, defined in RFC 2104. Because the key is folded into the hash twice, only a party holding that key can produce a matching tag — so a correct HMAC proves the message was not altered and came from someone who knows the secret. HMAC-SHA-256 outputs 256 bits, written here as 64 lowercase hex characters.

How to Use the HMAC Generator

  1. Paste the exact message bytes — Sign the payload byte for byte as the receiver will see it. A re-indented JSON body or a stray trailing newline produces a completely different tag, which is the single most common cause of a failed signature check.
  2. Enter the shared secret — The key is treated as UTF-8 text. RFC 2104 recommends a key at least as long as the hash output — 32 bytes for SHA-256 — and there is no benefit to a key longer than the algorithm's block size, since longer keys are hashed down first.
  3. Choose the hash algorithm — SHA-256 is the default and matches what most APIs specify. Pick SHA-384 or SHA-512 only when the other side explicitly requires it; a longer tag is not more secure against any practical attack on HMAC.
  4. Click Generate HMAC — The tag is computed with crypto.subtle.sign and shown as lowercase hexadecimal — two characters per byte, no separators, no 0x prefix.
  5. Convert the encoding if the API expects base64 — Many services want the same bytes in base64 rather than hex. The digest is identical; only the presentation differs. Decode the hex and re-encode it with the Encoder / Decoder if needed.
  6. Compare tags in constant time — When you verify a signature in your own code, use a constant-time comparison such as crypto.timingSafeEqual in Node or hmac.compare_digest in Python. A plain equality check leaks how many leading bytes matched.

How HMAC Works

HMAC is not a hash function of its own. It is a construction, standardised in RFC 2104 and restated in FIPS 198-1, that turns any ordinary hash function into a keyed one. The definition is a nested double hash:

HMAC(K, M) = H( (K′ ⊕ opad) ‖ H( (K′ ⊕ ipad) ‖ M ) )

H is the underlying hash, M is your message and K′ is the key adjusted to the hash's internal block size — hashed down first if it is too long, right-padded with zero bytes if it is too short. ipad is the byte 0x36 repeated across a full block and opad is 0x5C repeated the same way; the symbol ⊕ is a byte-wise XOR and ‖ is concatenation. The inner hash absorbs the message, the outer hash covers the inner result, and the key is mixed into both.

That nesting is the whole point. A naive keyed hash such as H(secret ‖ message) is broken by a length extension attack on Merkle–Damgård constructions like SHA-256: an attacker who knows a valid digest can append data and compute a valid digest for the longer message without ever learning the key. Wrapping the inner digest in a second keyed hash removes that property, which is why the awkward-looking double pass exists rather than something simpler.

What This Tool Runs

Your message and key are converted to bytes with TextEncoder, which always produces UTF-8. The key is then imported through crypto.subtle.importKey as a raw HMAC key marked non-extractable and usable only for signing, and the tag is produced by crypto.subtle.sign. This is the browser's native Web Crypto API — the same vetted implementation the browser uses for TLS-adjacent work — not a JavaScript reimplementation of SHA-2. The resulting ArrayBuffer is rendered as lowercase hex, one zero-padded pair per byte.

Algorithm Reference

AlgorithmTag lengthHex charactersHash block size
HMAC-SHA-256256 bits / 32 bytes6464 bytes
HMAC-SHA-384384 bits / 48 bytes96128 bytes
HMAC-SHA-512512 bits / 64 bytes128128 bytes

The tag length is fixed by the algorithm and never depends on how long your message is — a one-character message and a ten-megabyte file both yield exactly 64 hex characters under SHA-256. If the string you produced is a different length from the one an API returns, you are almost certainly looking at a different encoding rather than a different key.

What HMAC Does and Does Not Give You

HMAC provides integrity and authenticity: the message has not changed, and it came from a holder of the key. It does not provide confidentiality — the message travels in the clear alongside its tag, so HMAC is not encryption. It also does not provide non-repudiation: because the secret is shared, either party could have produced any given tag, so an HMAC cannot prove to a third party who sent a message. When that matters, an asymmetric signature such as RSA or ECDSA is the right primitive.

Replay is the other gap. A captured request and its valid tag stay valid forever unless you sign something that changes, which is why signing schemes fold a timestamp and a nonce into the signed string and reject requests outside a short window. Sign the canonical string the receiver will rebuild — method, path, timestamp, body digest — rather than the body alone.

Pressing Generate HMAC stores the message and secret in the page URL so a result can be bookmarked or reloaded. Treat that address bar as containing your key: do not copy the link into a chat, ticket or bug report, and press Clear when you are done. For the same reason, use a throwaway key when you are only exploring how HMAC behaves, and rotate any production secret you have pasted into a browser tool.

Frequently Asked Questions

A regular hash only proves data integrity. HMAC combines the hash with a secret key, proving both integrity and authenticity — meaning you know the message was created by someone who holds the key.

HMAC is used for API request signing (Stripe, AWS, GitHub webhooks), JWT tokens, session cookies, and message authentication in protocols like TLS and IPsec.

The computation is entirely local: TextEncoder and crypto.subtle run in your tab and nothing is posted to a server. One caveat worth knowing — generating a tag also writes the message and key into the page URL so the result can be bookmarked, so the address bar holds your secret until you press Clear. Never share that link, and prefer a test key here over a live production secret.

In order of likelihood: the encoding differs (this tool emits lowercase hex, many APIs want base64 of the same bytes); the signed string is not byte-identical, usually because JSON was reformatted, a trailing newline crept in, or the body was signed before rather than after serialisation; the API signs a canonical string of method, path, timestamp and body digest rather than the body alone; or the key is being interpreted as hex or base64 bytes on their side while this tool treats it as UTF-8 text.

SHA-256 unless the other side specifies otherwise — it is the default for AWS Signature v4, Stripe and GitHub webhooks, and JWT's HS256. SHA-384 and SHA-512 produce longer tags but bring no meaningful security gain for message authentication, and on 32-bit environments SHA-512 can be slower. Match whatever the specification you are implementing names; there is no interoperability if you guess.

RFC 2104 advises a key of at least the hash output length, so 32 random bytes for SHA-256. Use bytes from a cryptographic random source rather than a memorable phrase, because HMAC gives an attacker who captures one message and tag an offline target to guess against. Keys longer than the hash block size (64 bytes for SHA-256) are hashed down before use, so extra length past that adds nothing.

No, and the difference matters. HMAC authenticates but does not hide: anyone who intercepts the message can read it, they simply cannot change it without invalidating the tag. HMAC is also not reversible — you cannot recover the message from the tag. If you need secrecy as well as integrity, use an authenticated encryption mode such as AES-GCM, which handles both in one step.

crypto.subtle is only exposed in a secure context, meaning HTTPS or localhost. On a plain http:// origin the property is undefined and key import throws immediately. The same restriction applies to your own code, which is why a signing routine that works locally can break the moment it is served over HTTP.

Use Cases

API Request Signing

Sign API requests with HMAC-SHA256 to prove authenticity and prevent replay attacks on sensitive endpoints.

Webhook Verification

Verify that incoming webhooks from services like Stripe or GitHub haven't been forged or tampered with.

JWT Token Signing

Generate HMAC signatures for JSON Web Tokens to ensure token integrity and prevent tampering.

Expiring Download Links

Sign a path plus an expiry timestamp so a CDN or storage bucket can serve a private file to anyone holding the link, and refuse it once the timestamp has passed.

Debugging a Rejected Signature

Reproduce a failing webhook check by hand: paste the exact raw body and the endpoint secret here, and compare the tag against the header the provider sent to see whether the mismatch is the key or the signed string.

Cross-Language Test Vectors

Confirm that a Python, Go and JavaScript implementation all agree by checking each against the same message, key and algorithm before wiring them into a service that has to interoperate.