Skip to main content

HMAC Generator and Verifier

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.

  • Clipboard

Embed this widget

Customize the result, check the live preview, then copy the code.

Preview

Embed code type

Code to copy

Responsive and automatically resized by Bethemesh.

HMAC signature

Hexadecimal or Base64, with or without a prefix such as sha256=.

Was this tool useful?

How does this tool work?

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.

How to use this tool

  1. Enter the message and the key

    Paste the exact message to sign, for example a webhook's raw body, then the shared secret key.

  2. Choose the algorithm and format

    Select SHA-1, SHA-256, SHA-384 or SHA-512 and hex or Base64 output, depending on what the service expects.

  3. Compare with the received signature

    Optionally paste the expected signature, with or without a prefix such as sha256=: the HMAC and the verification result update as you type.

HMAC authentication

HMAC authentication

HMAC(K, m) = H((K' XOR opad) || H((K' XOR ipad) || m))

Use cases

Verify a GitHub webhook

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.

Debug a Stripe signature

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.

Check a Shopify webhook

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.

Examples

Reference HMAC-SHA256 signature

Input

Message: The quick brown fox jumps over the lazy dog; Secret key: key; Algorithm: SHA-256; Encoding: Hexadecimal

Result

Computed signature: f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8

Tips and best practices

  • Sign the raw body exactly as it was received: JSON that has been reformatted, re-indented or had its keys reordered gives a completely different signature.
  • Watch out for invisible spaces and line breaks around the secret: a key copied with a trailing newline produces a different HMAC.
  • On the server, always compare with a constant-time function (crypto.timingSafeEqual, hmac.compare_digest) and, for Stripe or Slack, reject old timestamps to block replay attacks.

Sources and references

Frequently asked questions

What is the difference between an HMAC and a hash?

Anyone 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.

Why doesn't my webhook signature match?

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.

Is HMAC-SHA-1 still secure?

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.

How long should the key be?

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.

Can an HMAC be decrypted to recover the message?

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.

Is it safe to enter a production webhook secret here?

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.

Similar tools

Compute MD5, SHA-1, SHA-256, SHA-384 and SHA-512 hashes of a text or file in one go.

Security & privacyFeaturedUse this tool

Check whether two hashes or checksums match, regardless of case, spaces or colons.

Security & privacyUse this tool

Generate secure random tokens from 8 to 256 bytes in hex, Base64 or Base64URL, with an optional prefix.

Security & privacyUse this tool