◇ Security & Cryptography

HMAC Generator & Webhook Signature Verifier

Generate HMAC-SHA1/256/384/512 in hex or Base64, and verify GitHub, Stripe, Slack and Shopify webhook signatures against the raw request body.

SHA-1 to SHA-512 GitHub / Stripe / Slack / Shopify Constant-time compare Keys never stored

Loading HMAC Generator…

What this page sends

  • Your input: Keys and bodies are processed with the Web Crypto API in this tab. They are not saved, not put in a link and not sent to a server.
  • Page load: Loading the page requests HTML, scripts and images from ByteKiln, fonts from Google Fonts, and sends Google Analytics page views, tool-usage events and catalog interactions (tool/category IDs, result status and whether a click followed search — never your input, output or search terms). Privacy & sharing

How the HMAC Generator & Webhook Signature Verifier Works

Every serious webhook provider signs its requests so you can prove they came from them: GitHub, Stripe, Slack, Shopify and hundreds of others compute an HMAC over the request body with a secret only you and they know. Verifying it is a few lines of code — and debugging it when it fails is an afternoon, because the signature covers exact bytes and every framework wants to parse and re-serialize the body first. This tool has two modes. Generate computes HMAC-SHA1, SHA-256, SHA-384 or SHA-512 over text, hex or Base64 input with a text, hex or Base64 key, and shows the result as lower- and upper-case hex, Base64 and Base64URL. Verify takes a raw body, your signing secret and the signature header, applies the provider's own rules — what exactly is signed, how the signature is encoded, which header carries it — and tells you whether it matches, what the expected value is, and which of the usual mistakes to check. Test vectors from RFC 4231 are part of the test suite.

HMAC

HMAC(K, m) = H((K ⊕ opad) ‖ H((K ⊕ ipad) ‖ m)). The tool uses crypto.subtle.sign with an HMAC key imported from your key bytes, so the hashing is done by the browser's audited implementation. An empty message is valid and has an HMAC like any other.

Provider rules

GitHub signs the body; Stripe signs "t.body" and may send several v1 signatures during secret rotation; Slack signs "v0:t:body" with the request timestamp; Shopify signs the body and Base64-encodes the result. Stripe and Slack timestamps older than five minutes are flagged, since both recommend rejecting them to prevent replay.

Comparison

Signatures are decoded to bytes and compared in constant time. Hex comparison is therefore case-insensitive, and "sha256=" or "v0=" prefixes are handled per provider.

Input checks

The tool warns about a trailing newline in the body, CRLF line endings, a key wrapped in quotes and leading or trailing whitespace in the key — the four ways a correct secret and body most often produce the wrong HMAC.

Limitations

  • SHA-1, SHA-256, SHA-384 and SHA-512 only; MD5-based HMAC and SHA-3 are not available in Web Crypto.
  • Webhook checks depend on the exact raw body. Copying a body out of a log or a pretty-printed viewer can change whitespace or escaping, so a mismatch here doesn't always mean the secret is wrong.
  • Provider presets cover GitHub, Stripe, Slack and Shopify; other providers work in the generic mode if you know what they sign.
  • Bodies are text; binary payloads can't be pasted.

FAQ

Short answers for the things developers usually ask before trusting a tool.

Is my key uploaded?

No. HMACs are computed with your browser's Web Crypto API. Keys are not saved, not put in any link and not sent to a server.

Why doesn't my webhook signature match?

Almost always because the body isn't byte-for-byte what was signed: it was parsed and re-serialized as JSON, pretty-printed, had a trailing newline added when copied, or had its line endings changed. Verify against the raw request body. The other common cause is using an API key instead of the endpoint's signing secret.

What exactly do GitHub, Stripe, Slack and Shopify sign?

GitHub: HMAC-SHA256 of the body, sent as sha256=<hex> in X-Hub-Signature-256. Stripe: HMAC-SHA256 of "timestamp.body", sent as t=…,v1=<hex> in Stripe-Signature. Slack: HMAC-SHA256 of "v0:timestamp:body", sent as v0=<hex> in X-Slack-Signature. Shopify: HMAC-SHA256 of the body, Base64-encoded in X-Shopify-Hmac-Sha256.

Why use a constant-time comparison?

Comparing signatures with == can return as soon as the first byte differs, and the timing can leak how many bytes were right. The verifier compares every byte regardless, like crypto.timingSafeEqual in Node or CryptographicOperations.FixedTimeEquals in .NET — use those in your server code too.

Is HMAC the same as hashing?

No. A hash like SHA-256 can be computed by anyone; an HMAC mixes in a secret key, so only someone with the key can produce a matching value. That's what proves a webhook came from the sender.

Can I use a hex or Base64 key?

Yes. Choose whether the key is text, hex or Base64 — the same characters give different key bytes, and so a different HMAC.

Related tools

Useful follow-ups when one conversion usually turns into three more.