HMAC authentication
HMAC(K, m) = H((K' XOR opad) || H((K' XOR ipad) || m))
Compute the HMAC of a message with a secret key, in hex or Base64, and compare it with an expected signature (sha256= prefix accepted) to verify a GitHub, Stripe or Shopify webhook.
Hexadecimal or Base64, with or without a prefix such as sha256=.
This tool computes the HMAC of a message with a secret key, using SHA-1, SHA-256, SHA-384 or SHA-512, and compares it with an expected signature. It is mainly for developers who integrate or debug GitHub, Stripe or Shopify webhooks and need to know whether a failure comes from the secret, the message body or their code.
An HMAC (RFC 2104, FIPS 198-1) combines a hash function with a secret key: HMAC(K, m) = H((K ⊕ opad) ‖ H((K ⊕ ipad) ‖ m)). This double pass makes the value impossible to produce without the key and prevents the length-extension attack that affects a plain SHA-256(key ‖ message). With the key "key" and the message "The quick brown fox jumps over the lazy dog", HMAC-SHA-256 gives f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8 in hex, or 97yD9DBThCSxMpjmqm+xQ+9NWaFJRhdZl0edvC0aPNg= in Base64. The key is used as typed, message and key are encoded as UTF-8, and the computation runs through the browser's Web Crypto API.
Most providers sign the raw request body. GitHub sends X-Hub-Signature-256: sha256=<hex>, Shopify sends X-Shopify-Hmac-Sha256 in Base64, and Stripe signs the string "timestamp.body" and puts the hex value after v1= in the Stripe-Signature header. So pick hex or Base64 output depending on the provider, then paste the signature you received into the optional field: prefixes such as "sha256=" are accepted and the result updates as you type. The comparison runs in constant time, as GitHub recommends for server code.
Paste the exact message to sign, for example a webhook's raw body, then the shared secret key.
Select SHA-1, SHA-256, SHA-384 or SHA-512 and hex or Base64 output, depending on what the service expects.
Optionally paste the expected signature, with or without a prefix such as sha256=: the HMAC and the verification result update as you type.
HMAC(K, m) = H((K' XOR opad) || H((K' XOR ipad) || m))
Copy the raw payload and the X-Hub-Signature-256 header from the webhook's Recent Deliveries tab, enter the secret and compare. If the value matches here but not on your server, your framework is changing the body before verification.
Rebuild the signed string "t.body" from the Stripe-Signature header and the raw body, compute the HMAC-SHA-256 with your whsec_… secret and compare it with the v1 value to pinpoint why verification fails.
Shopify signs the raw body with HMAC-SHA-256 and sends the result in Base64 in X-Shopify-Hmac-Sha256. Choose Base64 output and paste the header to confirm you are using the right app secret.
Input
Message: The quick brown fox jumps over the lazy dog; Secret key: key; Algorithm: SHA-256; Encoding: HexadecimalResult
Computed signature: f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8Anyone can compute a hash such as SHA-256: it proves integrity, not origin. An HMAC adds a secret key, so only someone holding that key can produce the correct value. It therefore authenticates the sender as well as detecting any change.
Most often the body was changed before the computation: JSON parsed and re-serialised by the framework, a different encoding or added whitespace. Other common causes are the wrong secret (test instead of production), the wrong output format (hex instead of Base64) or, for Stripe, forgetting the timestamp in the signed string.
For message authentication, yes: SHA-1 collisions do not allow forging an HMAC-SHA-1 without the key, and it is still used, for example by TOTP. For any new system, prefer HMAC-SHA-256, now the standard for webhooks. GitHub keeps the SHA-1 X-Hub-Signature header only for backward compatibility.
RFC 2104 recommends a key at least as long as the hash output, which is 32 bytes for HMAC-SHA-256. A key longer than the block size (64 bytes for SHA-256) is hashed first, so it adds no extra security. Generate it randomly rather than picking a password.
No, an HMAC is not encryption: it does not contain the message and cannot be used to rebuild it. The message is usually sent in clear text alongside the signature anyway. To make content unreadable you need encryption such as AES-GCM.
The computation happens only in your browser with Web Crypto: neither the key nor the message is transmitted. As a matter of principle, prefer a test secret, or rotate the secret after a debugging session on a shared computer.
Related tools
Tools similar or complementary to this one.
Compute MD5, SHA-1, SHA-256, SHA-384 and SHA-512 hashes of a text or file in one go.
Check whether two hashes or checksums match, regardless of case, spaces or colons.
Generate secure random tokens from 8 to 256 bytes in hex, Base64 or Base64URL, with an optional prefix.
Distinguish hashing from encryption and encoding, understand SHA-256 and SHA-3, collisions and the limits of a hash without authentication.
Learn when to use encryption, hashing, HMAC or key derivation for confidentiality, integrity, authentication and password handling.
Understand how SRI hashes help detect unexpected changes to static third-party scripts and stylesheets, and where SRI does not apply.
Understand the layers that protect a website: HTTPS, HTTP security headers, CSP, SRI, authentication, passwords and integrity.