HMAC Generator & Verifier

Updated July 2026

An HMAC is a keyed hash — a signature computed from a message and a secret key that proves the message wasn't tampered with and came from someone who knows the key. This tool computes and verifies HMAC-SHA1, SHA-256, SHA-384 and SHA-512 signatures entirely in your browser: your message and secret key never leave your device.

Most common use: verifying webhook signatures and signing API requests. GitHub sends X-Hub-Signature-256 (HMAC-SHA256 of the raw body, hex), Stripe sends Stripe-Signature, and countless APIs sign requests the same way. Paste the payload, the shared secret and the expected signature below to check your integration.
The exact text to sign. For webhooks, use the raw body bytes — not re-serialized JSON.
Interpreted as UTF-8 text. Never uploaded — everything runs on your device.
HMAC signature
Updates as you type. Click the signature to copy it.
Compared against the computed HMAC, ignoring case, whitespace and encoding.

How an HMAC works — and why it beats a plain hash

A plain hash like SHA-256 turns any input into a fixed-length fingerprint, but it proves only that data wasn't corrupted — anyone can compute it. An HMAC (hash-based message authentication code) adds a secret key to the mix: the standard construction is HMAC(K, m) = H((K ⊕ opad) ‖ H((K ⊕ ipad) ‖ m)) — the key is XOR-padded, the message is hashed once with the inner key, and that digest is hashed again with the outer key. Only someone who holds the same key can produce or verify a valid signature, which is why HMACs are used to authenticate webhooks, API requests, session tokens and JWTs (the HS256 algorithm is exactly HMAC-SHA256).

You might wonder why anyone bothers with that two-pass construction instead of simply hashing secret + message. The answer is the length-extension attack: SHA-256 (like SHA-1 and SHA-512) processes input in blocks and exposes its full internal state as the digest, so an attacker who knows SHA-256(secret ‖ message) can keep hashing from that state and forge a valid digest for secret ‖ message ‖ padding ‖ anythingwithout ever knowing the secret. HMAC's nested, double-keyed design closes that hole completely, which is why every serious API uses HMAC rather than an ad-hoc concatenation.

This tool feeds your UTF-8 message and key to the browser's built-in Web Crypto API (crypto.subtle.importKey + crypto.subtle.sign), so the computation is native, fast and entirely local.

Choosing the hash and the encoding

Use HMAC-SHA256 by default — it is what GitHub, Stripe, Slack, Shopify and most modern APIs specify, and it is the hash behind JWT's HS256. SHA-384/512 are equally fine if a spec calls for them. HMAC-SHA1 deserves a footnote: although SHA-1 itself is broken for collisions, the HMAC construction doesn't rely on collision resistance, so HMAC-SHA1 is not practically broken — but it survives mainly in legacy APIs (e.g. older OAuth 1.0 signatures), so use it only when the other side requires it.

The raw output of an HMAC is bytes; what you see is an encoding of those bytes. Hex (lowercase, two characters per byte) is what most webhook headers use — GitHub's sha256=… value is 64 hex characters. Base64 is one-third shorter and common in Authorization headers and AWS-style request signing. They are the same signature, just written differently — which is why the verifier above accepts either.

Test vector: key key, message The quick brown fox jumps over the lazy dog

AlgorithmHMAC (hex)
HMAC-SHA1de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9
HMAC-SHA256f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8
HMAC-SHA512b42af09057bac1e2d41708e48a902e09b5ff7f12ab428a4fe86653c73dd248fb82f948a549f7b791a5b41915ee4d1ec3935357e4e2317250d0372afa2ebeeb3a

Type those exact inputs above and you should see exactly these values — a quick sanity check that any HMAC implementation should pass.

Debug checklist: "my webhook signature doesn't match"

  • Sign the raw body bytes, not parsed-then-re-serialized JSON. JSON.parseJSON.stringify reorders nothing in theory but changes whitespace and unicode escaping in practice — one byte off and the HMAC is completely different.
  • Read the exact header the provider documents: GitHub uses X-Hub-Signature-256 (not the older SHA-1 X-Hub-Signature), Stripe uses Stripe-Signature, Slack uses X-Slack-Signature.
  • Strip the prefix and match the encoding. GitHub's value is sha256= + lowercase hex; some APIs send Base64. Comparing hex against Base64 will never match.
  • Check timestamp schemes. Stripe and Slack don't sign the body alone — they sign timestamp + "." + body (Stripe) or "v0:" + timestamp + ":" + body (Slack). Recreate the exact signed string, including separators.
  • Verify the secret itself — test vs. live keys, trailing newlines from copy-paste, and whether the provider expects the secret as text or decoded from Base64.

Related tools: generate plain digests with the hash generator, decode and inspect HS256 tokens with the JWT decoder, or convert signatures between text and Base64 with the Base64 encoder/decoder.

Frequently asked questions

What is an HMAC?
An HMAC (hash-based message authentication code) is a keyed hash: it mixes a secret key into a cryptographic hash such as SHA-256 to produce a short signature of a message. Anyone who holds the same key can recompute the signature and confirm both that the message was not altered (integrity) and that it came from someone who knows the key (authenticity).
What's the difference between an HMAC and a regular hash?
A plain hash like SHA-256 depends only on the message, so anyone can compute it — it proves integrity but not who produced it. An HMAC also depends on a secret key, so only parties holding the key can create or verify a valid signature. Naively concatenating the key with the message and hashing it is not a safe substitute, because plain SHA-256 is vulnerable to length-extension attacks; the HMAC construction was designed specifically to avoid that.
Is my secret key sent anywhere?
No. The message and the secret key are processed entirely on your own device using the browser's built-in Web Crypto API (crypto.subtle). Nothing is uploaded, logged or stored — you can load the page, disconnect from the internet and keep computing signatures.
Which algorithm should I choose?
Use HMAC-SHA256 unless the service you are integrating with specifies otherwise — it is the de-facto standard for webhooks, API signing and JWTs (HS256). SHA-384 and SHA-512 are fine too. HMAC-SHA1 is still cryptographically acceptable inside the HMAC construction, but it survives mostly in legacy APIs; pick it only when the other side requires it.
How do I verify a webhook signature?
Take the raw, unmodified request body exactly as it arrived (the bytes, not re-serialized JSON), compute an HMAC over it with the shared secret using the algorithm the provider documents, and compare the result to the signature header — for example GitHub's X-Hub-Signature-256 (hex, prefixed with sha256=) or Stripe's Stripe-Signature (hex, with a timestamp that must also be included in the signed payload). Paste the body, secret and the expected value into this tool to check your math.
Can an HMAC be reversed?
No. Like any cryptographic hash, an HMAC is one-way: the original message cannot be recovered from the signature. Verification works the other way around — you recompute the HMAC with the same secret key and compare. That also means an HMAC can only be verified by someone who holds the key; without it, the signature is just an opaque string.
⚡ HMAC Generator & Verifier — by larely ↗

Related tools

Test Data Generator

Generate fake mock data as CSV or JSON for testing.

Word Counter

Word and character counter with reading time — runs privately in your browser.

Text Case Converter

Convert text to UPPER, lower, Title, Sentence, camelCase, snake_case and more.

PPI / Screen Size Calculator

Pixels per inch, dot pitch, megapixels and aspect ratio for any screen.

Color Converter & Contrast Checker

Convert HEX, RGB and HSL colors and check WCAG contrast ratios.

JSON Formatter & Validator

Beautify, validate and minify JSON — private, in your browser.

Morse Code Translator

Translate text to Morse code and back, with audio playback.

Password Generator

Generate strong, random passwords and passphrases privately in your browser.

Base64 Encoder / Decoder

Encode and decode Base64 text in your browser.

Lorem Ipsum Generator

Generate placeholder text by paragraphs, sentences or words.

URL Slug Generator

Turn any title into a clean, SEO-friendly URL slug.

CSS Gradient Generator

Design a linear or radial CSS gradient and copy the code.

Browse all 251 free tools →