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.
Generate HMAC-SHA1/256/384/512 in hex or Base64, and verify GitHub, Stripe, Slack and Shopify webhook signatures against the raw request body.
Loading HMAC Generator…
Loading HMAC Generator…
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(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.
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.
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.
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.
Short answers for the things developers usually ask before trusting a tool.
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.
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.
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.
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.
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.
Yes. Choose whether the key is text, hex or Base64 — the same characters give different key bytes, and so a different HMAC.
Useful follow-ups when one conversion usually turns into three more.
Decode JWT header and payload locally so you can inspect claims and expiry quickly.
Create and sign JSON Web Tokens with HS256/384/512 for testing APIs — claim helpers for iat, exp, nbf and jti, secret encoding options, and warnings for common mistakes.
Generate MD5, SHA-1, SHA-256, SHA-384, and SHA-512 hashes from text.