HMAC Generator — Free Online Tool

Generate an HMAC signature from a message and secret key using SHA-256, SHA-1, SHA-384 or SHA-512. Hex or Base64 output, computed locally in your browser.

Use this free online HMAC Generator directly in your browser. No signup required, no data leaves your device. Part of Utilier — a collection of 133+ developer utilities.

What is HMAC Generator (SHA-256, SHA-1, SHA-384, SHA-512)?

An HMAC is a keyed message authentication code: it combines a secret key with a message through a hash function so that only someone holding the key can produce or check the resulting tag. This tool implements the construction from RFC 2104 and FIPS 198-1 over SHA-256, SHA-1, SHA-384 or SHA-512, and returns the tag as hex or Base64.

  • Two inputs, one tag: The Message box takes the exact bytes you want to authenticate; the Key box takes the shared secret. Change either one and the tag changes completely — that is the whole point, and it is why an HMAC proves both integrity and origin where a bare hash proves only integrity.
  • Four hash choices: SHA-256 is selected by default and is what most webhook and request-signing schemes use. SHA-1 is offered because HMAC-SHA-1 is still deployed in AWS Signature Version 2, older OAuth 1.0a implementations and some TOTP setups. SHA-384 and SHA-512 are there when a scheme asks for a longer tag.
  • Hex or Base64 output: Providers disagree about encoding: Stripe and GitHub publish hex signatures, Slack prefixes hex with a version marker, and many AWS and Twilio-style schemes use Base64. Switching the Output selector converts the same underlying bytes, so you can match whichever form appears in a header.
  • Keys are taken as raw UTF-8 bytes: The key string is encoded with TextEncoder and imported into Web Crypto as raw key material. That matches the common case where a secret is an ASCII token. If your secret is documented as Base64 or hex, decode it first — hashing the printable form gives a different, wrong tag.
  • Runs entirely in the page: Signing uses crypto.subtle.importKey and crypto.subtle.sign in your browser. The secret is never placed in a request body or written to a server log, which matters because a leaked HMAC key is equivalent to a leaked password.

Why use the HMAC Generator?

HMAC is the standard way to answer "did this message really come from the party I share a secret with, and did it arrive unchanged?", and having a reference implementation to compare against turns signature bugs from guesswork into a two-minute check.

  • Debug webhook verification: When a webhook signature check fails, the question is whether your code hashed the wrong bytes, used the wrong encoding, or has the wrong secret. Reproducing the tag here with the documented string-to-sign isolates which one it is — and providers rarely tell you more than "invalid signature".
  • Authenticity, not just integrity: Anyone can recompute a SHA-256 digest over a modified payload, so an unkeyed hash sent alongside data proves nothing about the sender. An HMAC cannot be recomputed without the key, which is why every serious webhook and API-signing scheme uses one.
  • Immune to length-extension by design: The naive alternative, hashing key concatenated with message, is vulnerable to length-extension against Merkle–Damgård hashes like SHA-256: an attacker who sees a tag can append data and compute a valid tag without knowing the key. HMAC's nested inner and outer hashing blocks that attack, which is why the construction exists at all.
  • Produce test fixtures with known values: Unit tests for signature verification need a tag you trust. Generate it here from a fixed message and key so the test asserts a real value rather than whatever your own code happens to output — which would pass even if both sides were wrong.
  • Keeps secrets off the wire: Pasting a production signing secret into a server-side online tool hands it to a third party. Here the key stays in the tab; the safest habit is still to use a scratch key when experimenting.

When to use the HMAC Generator

Reach for it whenever a secret key and a hash function are combined to authenticate something.

  • Verifying inbound webhooks from Stripe, GitHub, Slack, Shopify, Twilio or a partner API, where the provider sends an HMAC over the raw request body.
  • Building outbound request signatures: assembling a canonical string-to-sign, signing it, and comparing your result against the reference tag before you debug transport code.
  • Implementing or troubleshooting AWS Signature Version 4, which chains four HMAC-SHA-256 operations to derive a signing key from the secret, date, region and service.
  • Generating short-lived signed URLs or download tokens where a tag over a path plus expiry timestamp gates access.
  • Checking a TOTP or HOTP implementation, since both are HMAC-SHA-1 (or SHA-256/512) over a counter, per RFC 4226 and RFC 6238.
  • Producing an integrity tag for data at rest — a config blob, a cookie value, a queue message — so tampering is detectable when it is read back.
  • Writing tests, documentation or training material where a known-good HMAC value is needed.

How to use the HMAC Generator

Four controls, and the tag recomputes as you type. Nothing happens until a key is present — the status line says "Enter a key" while it is empty.

  1. Paste the exact message: Put the string-to-sign in the Message box, byte for byte. For webhooks this is usually the raw request body, sometimes prefixed with a timestamp and a separator that the provider documents — reformatted or re-serialised JSON will not match.
  2. Enter the secret key: Paste the shared secret into the Key box. Use its literal characters; if the provider documents the secret as Base64 or hex, decode it to bytes first and sign with those bytes instead.
  3. Pick the hash: SHA-256 is the default and covers most modern schemes. Choose SHA-1 for legacy signing, TOTP, or AWS SigV2; SHA-384 or SHA-512 when the spec asks for a longer tag.
  4. Choose hex or Base64: Match the form that appears in the provider's header. The same tag is 64 hex characters or 44 Base64 characters for SHA-256 — if your value is 44 characters and ends with =, it is Base64.
  5. Copy and compare correctly: Copy the tag with the button next to the output. When comparing in code, use a constant-time comparison — crypto.timingSafeEqual in Node, hash_equals in PHP, hmac.compare_digest in Python — never == on strings.
  6. Clear the key when finished: Use the clear control in the message header and blank the key field once you are done, especially if you pasted a real production secret.

Key features

  • RFC 2104 construction via Web Crypto: Signing goes through the browser's native HMAC implementation, so results match what your own crypto.subtle code will produce with the same parameters.
  • Four hash algorithms: SHA-256 (default), SHA-1, SHA-384 and SHA-512, switchable without retyping the message or key.
  • Hex and Base64 in one click: The Output selector re-renders the same tag bytes, so you can compare against either encoding a provider happens to use.
  • Live recomputation: Message, key, algorithm and encoding changes all trigger a refresh about 150 ms after your last keystroke.
  • Explicit missing-key state: The output stays empty and the status line prompts for a key rather than silently signing with an empty secret, which would produce a plausible-looking but meaningless tag.
  • Local-only signing: Keys and messages are processed in the page; there is no network request, so secrets stay out of server logs and request bodies.

Common use cases

  • Webhook signature verification: Reproduce the X-Hub-Signature-256, Stripe-Signature or X-Slack-Signature value locally and find out whether your handler is hashing the parsed body instead of the raw one.
  • API request signing: Verify each stage of a canonical request and signing-key derivation, including the multi-step HMAC chain in AWS Signature Version 4.
  • Signed URLs and download tokens: Generate the tag for a path plus expiry pair, then confirm your gateway or CDN rule accepts and rejects the values you expect.
  • One-time password debugging: Check HOTP and TOTP behaviour, which are HMAC over an 8-byte counter followed by dynamic truncation.
  • Tamper-evident data at rest: Tag cookies, cache entries or queue payloads so a modified value is rejected on read instead of trusted.
  • Test fixtures and documentation: Produce known-good tags for unit tests and runbooks so signature checks are asserted against real values.

Examples

The first example is the published RFC 4231 test vector, so you can use it to confirm any implementation. All values were computed from the exact bytes shown.

RFC 4231 test case 2 — a known-good vector

Key: Jefe
Message: what do ya want for nothing?
HMAC-SHA-1: effcdf6ae5eb2fa2d27416d5f184df9c259a7c79
HMAC-SHA-256: 5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843
HMAC-SHA-512: 164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737

These are the values published in RFC 4231. If your library reproduces them, its HMAC is correct and any remaining mismatch is in the bytes you are feeding it.

Same tag, hex versus Base64

Key: secret
Message: hello world
Hash: SHA-256
Hex: 734cc62f32841568f45715aeb9f4d7891324e6d948e4c6c60c0621cdac48623a
Base64: c0zGLzKEFWj0VxWuufTXiRMk5tlI5MbGDAYhzaxIYjo=

One 32-byte tag, two renderings: 64 hex characters or 44 Base64 characters. A signature ending in = is Base64, not hex.

Changing the algorithm changes everything

Key: key
Message: The quick brown fox jumps over the lazy dog
HMAC-SHA-1: de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9
HMAC-SHA-256: f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8
HMAC-SHA-384: d7f4727e2c0b39ae0f1e40cc96f60242d5b7801841cea6fc592c5d3e1ae50700582a96cf35e1e554995fe4e03381c237
HMAC-SHA-512: b42af09057bac1e2d41708e48a902e09b5ff7f12ab428a4fe86653c73dd248fb82f948a549f7b791a5b41915ee4d1ec3935357e4e2317250d0372afa2ebeeb3a

Same key and message, four different tags. If a provider says SHA-256 and you send SHA-1, nothing about the failure will point at the algorithm.

One character of message changed

Key: secret
Message: hello worlds
HMAC-SHA-256: 4a309ef3cb894e58fef4d3f25557dcef5abe15185d56959859dc43de78346499

Compare with 734cc62f… for "hello world". Adding one letter produces an unrelated tag, which is why a webhook body must be verified before any parsing or re-serialisation.

A webhook-style string-to-sign

Key: my-secret-key
Message: GET/api/v1/orders1700000000
HMAC-SHA-256: c085a09a5070a1df191fc7852772b8401653cff059728205a0aad8be7f7d3dc9

Typical canonical form: method, path and timestamp concatenated with no separators. The exact concatenation rule is provider-specific and is the single most common source of signature mismatches.

Technical reference

How the construction works and what each option produces:

Definition
HMAC(K, m) = H((K' ⊕ opad) ‖ H((K' ⊕ ipad) ‖ m)), with ipad = 0x36 repeated and opad = 0x5c repeated, per RFC 2104 and FIPS 198-1
HMAC-SHA-1
160-bit tag — 40 hex characters or 28 Base64 characters; 64-byte block size
HMAC-SHA-256
256-bit tag — 64 hex characters or 44 Base64 characters; 64-byte block size
HMAC-SHA-384
384-bit tag — 96 hex characters or 64 Base64 characters; 128-byte block size
HMAC-SHA-512
512-bit tag — 128 hex characters or 88 Base64 characters; 128-byte block size
Key handling
Keys shorter than the block size are zero-padded to it; keys longer than the block size are hashed first and the digest used as the key
Recommended key length
At least the digest length (32 bytes for SHA-256). RFC 2104 notes that keys longer than the block size add no strength
Key and message encoding here
Both are encoded as UTF-8 before signing; the key is imported as raw key material

Common mistakes to avoid

Comparing signatures with == instead of a constant-time comparison

Why it happens: Ordinary string comparison returns as soon as it finds a differing character, so the time it takes leaks how many leading characters were correct. An attacker who can send many requests and measure response times can recover a valid tag one character at a time, turning an impossible brute-force into a few thousand requests. The vulnerability is entirely in the comparison, not the HMAC, so it survives using a perfectly good algorithm and key.

How to avoid it: Use the constant-time helper your platform provides: crypto.timingSafeEqual in Node.js, hash_equals in PHP, hmac.compare_digest in Python, subtle.ConstantTimeCompare in Go. Decode both sides to bytes of equal length first, since some helpers throw or leak on length mismatch. A common belt-and-braces pattern is to HMAC both values again with a random per-process key and compare those digests, which removes any timing signal even with a naive comparison.

Signing a re-serialised body instead of the raw bytes received

Why it happens: Webhook signatures are computed over the exact octets the provider transmitted. If your framework parses JSON into an object and you then re-serialise it to sign, key order, whitespace, Unicode escaping and number formatting can all differ — {"a":1, "b":2} and {"b":2,"a":1} are the same object and completely different bytes. Body parsers that consume the stream before your handler runs make this failure mode almost inevitable, and it presents as "signature invalid" on every single request.

How to avoid it: Capture the raw body before any parsing middleware touches it: express.raw() or the verify hook in body-parser, request.get_data() in Flask, the raw stream in your framework of choice. Verify the signature against those bytes, and only then parse. Log the byte length of what you verified during development and compare it against the provider's Content-Length so a truncated or transformed body is obvious.

Using the printable form of a key that is really Base64 or hex

Why it happens: Many providers issue secrets as Base64 or hex text representing random bytes. Signing with the characters of that text rather than the decoded bytes uses a different key entirely, so every tag is wrong even though the algorithm, message and encoding are all correct. Because both interpretations succeed without error, there is nothing to catch the mistake except a failing comparison — and the debugging instinct is usually to suspect the message instead.

How to avoid it: Read the provider's key documentation before writing any code, and note whether the secret is an opaque ASCII token (use it literally, as this tool does) or an encoded byte string (decode first). Check the length: a 44-character key ending in = is almost certainly Base64 for 32 bytes, and a 64-character all-hex key is almost certainly 32 bytes in hex. Verify with the provider's own worked example if they publish one.

Sending an unkeyed hash and calling it a signature

Why it happens: A SHA-256 digest of a payload proves only that the payload matches the digest. An attacker who modifies the payload simply recomputes the digest, and the receiver sees a consistent pair. Concatenating the key manually as SHA-256(key ‖ message) is not a fix either: against Merkle–Damgård hashes such as SHA-1 and SHA-256, that construction is vulnerable to length-extension, letting an attacker who has one valid tag append data and forge a tag for the longer message without ever learning the key.

How to avoid it: Use HMAC rather than inventing a construction — its nested inner and outer hashes are specifically what defeats length-extension, and it is standardised, reviewed and available in every runtime. Include a timestamp or nonce in the signed string and reject stale values so a captured request cannot be replayed. If you need signatures verifiable by parties who must not be able to forge them, move to asymmetric signing instead of a shared secret.

Reusing one HMAC key everywhere, forever

Why it happens: A shared secret used across environments and services means a leak anywhere — a debug log, a stack trace, a committed .env file, a screenshot in a ticket — compromises everything at once, and gives you no way to narrow down the source. Long-lived keys also accumulate exposure: every deploy, every contractor, every CI provider that ever held the value remains part of your risk surface indefinitely.

How to avoid it: Issue separate keys per environment and per integration, store them in a secret manager rather than source control, and rotate on a schedule. Support two active keys during rotation so verification accepts either the old or the new tag for an overlap window, then retire the old one. Where the scheme allows it, derive per-request signing keys from the master secret the way AWS SigV4 does, so a captured signing key is useless outside its date, region and service scope.

Frequently asked questions

What is the difference between HMAC and a plain hash?

A plain hash takes only the message; an HMAC takes the message and a secret key. That difference changes what the output proves. Anyone can compute SHA-256 over modified data and present a matching digest, so an unkeyed hash only detects accidental corruption when you already trust the digest's source. An HMAC tag cannot be produced without the key, so a valid tag shows the message came from a holder of the secret and was not altered in transit. If your goal is "prove this came from my partner", you need HMAC or a digital signature, not a hash.

Is HMAC-SHA-1 still safe to use?

HMAC-SHA-1 has no practical break today, because HMAC's security depends mainly on the hash's resistance to key-recovery and forgery rather than collision resistance — which is what SHA-1 lost. That is why RFC 9155 deprecated SHA-1 for TLS 1.2 signatures but explicitly left SHA-1 with HMAC in record protection alone. Even so, NIST is moving away from SHA-1 for all applications by the end of 2030, and new designs should use HMAC-SHA-256. Keep HMAC-SHA-1 only for interoperability with existing systems such as TOTP or older signing schemes, and plan the migration.

How long should an HMAC key be?

At least as long as the digest — 32 random bytes for HMAC-SHA-256. RFC 2104 recommends a key of at least the output length L and notes that keys longer than the hash's block size gain nothing, since they are hashed down to a digest before use. Just as important is that the key is random rather than memorable: a dictionary word as an HMAC secret can be brute-forced offline from a single captured message and tag. Generate keys with a cryptographic random source, store them in a secret manager, and never derive them from something guessable like a hostname or a date.

Why is my webhook signature verification failing?

In order of likelihood: you are hashing a re-serialised body instead of the raw bytes; the string-to-sign needs a prefix such as a timestamp and separator that you have omitted; the signature is Base64 and you are comparing hex, or vice versa; the header contains a version prefix like "sha256=" or "v1," that must be stripped; or the secret is the wrong environment's. Reproduce the tag here with the documented string-to-sign and the exact key, then compare against the header value character by character. Whichever component differs is your bug.

Can an HMAC be reversed to recover the key or message?

No. HMAC is a one-way function in both arguments — there is no decryption step, and the tag is a fixed 20 to 64 bytes regardless of message size, so the message cannot be reconstructed from it. Recovering the key requires brute force, which is infeasible for a properly random 32-byte secret but very feasible if the secret is a short or dictionary-based string, since an attacker with one message and tag can test candidates offline as fast as their hardware allows. That is the practical argument for random keys of full digest length.

Should I use HMAC or a digital signature like RSA or Ed25519?

Use HMAC when both parties can hold the same secret: it is far faster, produces short tags, and is simple to implement. Use asymmetric signing when the verifier must not be able to forge messages, when you cannot securely share a secret with every verifier, or when you need non-repudiation — a signature anyone can verify with a public key but only the private-key holder can create. This is exactly the choice JWT libraries expose as HS256 versus RS256 or EdDSA: HS256 is HMAC-SHA-256 with a shared secret, the others are public-key signatures.

Does the message or key encoding affect the HMAC?

Yes, completely. HMAC operates on bytes, so the tag depends on how your text became bytes. This tool encodes both the key and the message as UTF-8, which matches TextEncoder and the common ASCII-secret case. If either side encodes as UTF-16, Latin-1, or treats a Base64 secret as literal characters, the byte sequences differ and so do the tags — with no error to hint at it. When a scheme is specified, it will state the encoding; when both sides are yours, agree on UTF-8 explicitly and hash the same canonical string on each end.

References

Privacy and availability

  • Runs entirely in your browser — zero server processing
  • No signup or account required
  • Works offline once loaded
  • Fast, lightweight, no external dependencies
  • Available as a browser extension for Chrome and Firefox