✍️ Security

HMAC Generator & Verifier

Generate HMAC-SHA256 and HMAC-SHA512 signatures for webhook validation and API request signing. Verify incoming webhook payloads against their expected signatures. All cryptographic operations run in your browser via the Web Crypto API.

⚑ Webhook Presets
βœ… HMAC-SHA256 Signature
Enter a secret key and message above to generate the signature…
πŸ” Verify Signature

Paste an incoming webhook signature to verify it matches the computed HMAC above.

πŸ”Enter a signature to verify against the computed HMAC
πŸ“– Verification Code Examples
Privacy: HMAC computation uses the browser's native crypto.subtle.sign() API. Your secret key and payload never leave your browser.
πŸ“– How to Use This Tool
β–Ό
1
Select a webhook preset (GitHub, Stripe, Slack)
2
Enter your secret key and the message payload
3
Choose format: hex, base64, or sha256=hex
4
Paste a signature in Verify to check if it matches
πŸ“ Examples
GitHub webhook
Input: Secret + JSON body
Output: sha256=a1b2c3d4...

Quick Overview

The HMAC Generator computes HMAC-SHA256 and HMAC-SHA512 signatures using a secret key and a message payload, entirely within your browser. HMAC (Hash-based Message Authentication Code) is a cryptographic construct that combines a hash function with a shared secret to produce a signature that proves both the integrity of a message β€” that it has not been modified β€” and its authenticity β€” that it was produced by someone who knows the secret key. Unlike a plain hash, an HMAC cannot be forged without knowing the secret, making it the standard mechanism for securing webhooks and signing API requests.

Every major SaaS platform that delivers webhooks β€” GitHub, Stripe, Slack, Shopify, Twilio, and hundreds of others β€” uses HMAC-SHA256 signatures to allow receiving servers to verify that incoming HTTP requests genuinely came from the platform and were not injected by a third party. Understanding how to compute and verify these signatures is a fundamental skill for any backend engineer building integrations or for SREs responsible for securing event-driven infrastructure.

Technical Details

All HMAC computation uses the browser's native crypto.subtle.sign() API with the HMAC algorithm. The secret key is imported as a CryptoKey object using crypto.subtle.importKey(), which prevents the raw key bytes from being exposed to JavaScript code after import. The message and secret are encoded to UTF-8 bytes using the TextEncoder API before being passed to the cryptographic function. The resulting bytes can be formatted as lowercase hex, standard base64, URL-safe base64, or the sha256=hex prefixed format used by GitHub's webhook verification.

Common Use Cases

Best Practices & Tips

Always sign the raw, unparsed request body bytes β€” not a re-serialized version of the JSON. If your webhook handler parses the body into an object and then re-serializes it before computing the comparison HMAC, differences in key ordering or whitespace between the original payload and your re-serialized version will produce a different signature and a false-negative verification failure; capture and sign the exact bytes as received, before any JSON parsing. Rotate webhook secrets on a schedule and support two active secrets during the rotation window (verify against either), since most platforms don't offer a zero-downtime secret rotation mechanism on their own. Store the secret in a secrets manager (Vault, AWS Secrets Manager, or your CI/CD platform's encrypted secrets) rather than an environment variable baked into a container image β€” a leaked image layer should not also leak your webhook secret. Finally, when troubleshooting a signature mismatch, check encoding before assuming the secret is wrong: a secret with a trailing newline (common when copy-pasted from a terminal or a `.env` file) produces a completely different HMAC than the same secret without it, and this is one of the most common causes of "valid secret but invalid signature" reports.

Frequently Asked Questions

What is HMAC?

HMAC (Hash-based Message Authentication Code) is a cryptographic mechanism defined in RFC 2104 that uses a secret key combined with a hash function β€” typically SHA-256 or SHA-512 β€” to produce an authentication tag for a message. Unlike a plain hash, which anyone can compute from the data alone, an HMAC requires knowledge of the secret key to produce or verify. This makes HMAC suitable for proving both the integrity of a message (it has not been altered) and its authenticity (it came from someone who holds the same secret). The security of HMAC depends entirely on the secrecy and strength of the key, not on keeping the algorithm secret.

What are HMAC signatures used for?

HMAC signatures are primarily used for webhook payload verification, where a platform signs the HTTP request body with a shared secret so the receiving server can confirm the request is genuine. GitHub sends an X-Hub-Signature-256 header containing sha256=<hex>, Stripe sends a Stripe-Signature header with a timestamp and v1=<hex> components, Slack sends X-Slack-Signature as v0=<hex>, and Shopify sends X-Shopify-Hmac-Sha256 as base64-encoded HMAC. Beyond webhooks, HMAC is used in API authentication schemes, JWT signing (the HS256 and HS512 algorithms in JWTs use HMAC), cookie signing to prevent tampering, and as a key derivation building block in protocols like TLS.

Why should I use timing-safe comparison when verifying HMAC signatures?

Standard string equality operators short-circuit as soon as they find the first non-matching character, which means the comparison takes less time when the strings diverge early. An attacker making thousands of requests with subtly different signatures can measure response times to determine how many leading characters of their forged signature match the expected value β€” a technique called a timing side-channel attack. Over many requests, this information can be used to reconstruct a valid signature without knowing the secret key. Timing-safe comparison functions like crypto.timingSafeEqual in Node.js, hmac.compare_digest in Python, and hmac.Equal in Go always compare the full length of both strings regardless of where they diverge, eliminating this attack vector. Always use these functions in production webhook verification code.