✍️ HMAC Signature Generator
Compute HMAC-SHA256/384/512 signatures. All computation is local — nothing leaves your browser.
Why Your API or Webhook Might Be Lying to You — And How HMAC Fixes It
Imagine you run an e-commerce store. Your payment gateway sends a webhook when a transaction completes: {"event":"payment_success","amount":5000}. Your server receives it, marks the order as paid, and ships the product. Simple enough — until someone figures out your webhook URL and starts sending fake payment success events with crafted payloads. Without a way to verify that the request genuinely came from your payment gateway, you're shipping products for payments that never happened.
This exact attack vector has caused real financial losses for real businesses. And the solution has existed in cryptography for decades: HMAC, or Hash-based Message Authentication Code.
What HMAC Actually Does
HMAC combines a secret key with your message using a cryptographic hash function (SHA-256, SHA-384, or SHA-512) to produce a fixed-length signature. The critical property: without knowing the secret key, it is computationally infeasible to produce a valid HMAC for any message — even if an attacker can see thousands of valid message-signature pairs.
The algorithm works roughly like this: the key is first processed to match the hash function's block size. Then it is XORed with two different padding constants (the "inner" and "outer" pads) to produce two derived keys. The inner key is concatenated with the message and hashed. That hash output is then concatenated with the outer key and hashed again. This two-pass construction is what protects HMAC against length-extension attacks that would compromise simpler constructions like SHA256(key + message).
The output — the HMAC signature — is deterministic. Given the same message and secret key, you will always get the same signature. This means the recipient can independently compute the HMAC on their end and compare it to the one sent with the message. If they match, the message is authentic and untampered.
SHA-256 vs SHA-384 vs SHA-512: Which Should You Choose?
All three variants (HMAC-SHA-256, HMAC-SHA-384, HMAC-SHA-512) are secure for production use today. The differences are output length and computational cost on certain hardware.
HMAC-SHA-256 produces a 256-bit (64 hex character) output. It is the most widely supported, and is what GitHub, Stripe, Shopify, and most major webhook providers use by default. For the vast majority of use cases — webhook verification, API authentication, JWT signing — SHA-256 is more than sufficient.
HMAC-SHA-384 and HMAC-SHA-512 produce larger outputs (384 and 512 bits respectively). They use the SHA-2 family's 64-bit word operations internally, which means on 64-bit systems SHA-512 can actually be faster than SHA-256 for large messages. If you're operating in a high-security environment, building for long-term document signing, or working in contexts where post-quantum concerns are creeping in, the larger variants add margin.
For everyday webhook verification and API payload authentication: use SHA-256. It is the industry default and universally understood.
The Real-World Pattern: How Services Use HMAC
When Stripe sends a webhook to your endpoint, the HTTP request includes a header like Stripe-Signature: t=1690000000,v1=abc123.... The v1 value is HMAC-SHA-256 of a string constructed from the timestamp and request body, signed with your webhook signing secret. Your server replicates that computation and compares the result. If they match, you know the request came from Stripe and wasn't tampered with in transit.
GitHub webhooks work the same way via the X-Hub-Signature-256 header. Twilio uses X-Twilio-Signature. PayPal, Shopify, Slack, Discord — they all use HMAC for the same reason: it is simple, fast, and mathematically sound.
When comparing HMAC values in production code, always use a constant-time comparison function (like hmac.compare_digest in Python or crypto.timingSafeEqual in Node.js). A naive string comparison can leak timing information that allows an attacker to guess the correct HMAC one byte at a time.
Common Mistakes That Break HMAC Security
The cryptography behind HMAC is solid. The vulnerabilities in practice almost always come from implementation errors.
Weak or guessable secret keys. The security of HMAC depends entirely on the secrecy and entropy of the key. Using a short password, a dictionary word, or a predictable value like a timestamp defeats the purpose entirely. Generate your signing secrets using a cryptographically secure random number generator — at least 32 bytes for SHA-256, and store them in environment variables or a secrets manager, never in source code.
Not validating the timestamp. Stripe's signature scheme includes a timestamp and Stripe rejects requests where the timestamp is more than five minutes old. This prevents replay attacks, where an attacker captures a legitimate request and resends it minutes or hours later. If you are designing your own HMAC scheme, include a timestamp in the signed payload and check it.
Signing the wrong thing. The HMAC covers exactly what you sign and nothing more. If your code signs the parsed JSON object after deserialization, you may be signing a normalized version of the payload, not the raw bytes the sender signed. Always sign the raw request body before any parsing.
Key reuse across environments. Using the same signing secret in development, staging, and production means a compromise in any environment compromises all of them. Rotate keys between environments and have a rotation plan for production.
Using This Tool and Verifying Your Results
The HMAC generator on this page uses the browser's built-in Web Crypto API — specifically crypto.subtle.importKey and crypto.subtle.sign — to compute signatures. No data is sent to any server. The Web Crypto API is the same cryptographic engine used by your operating system's TLS stack, so the output is identical to what you would get from openssl dgst -sha256 -hmac "key" <<< "message" or Python's hmac.new(key, msg, hashlib.sha256).hexdigest().
You can verify this tool's output against the OpenSSL command line. For a message hello with key secret:
echo -n "hello" | openssl dgst -sha256 -hmac "secret"
This should produce 88aab3ede8d3adf94d26ab90d3bafd4a2083070c3bcce9c014ee04a443847c0b. Enter the same values in the tool above and you will see the exact same output.
HMAC is one of those tools that, once you understand it, you start seeing it everywhere — and you start noticing its absence in systems that should be using it but are not. Building it into your webhook handlers and API authentication flows is one of the highest-leverage security improvements you can make.