HMAC Generator
Computes an HMAC over a message using a secret key — SHA-1, SHA-256, SHA-384 or SHA-512 — through the browser's Web Crypto API. Useful for verifying a webhook signature by hand, testing an API integration that signs requests, or just understanding what HMAC actually produces before you implement it in code.
Why HMAC exists as a separate thing from "just hash it"
A plain hash of a message proves the message hasn't changed, but anyone can compute it — there's no secret involved, so it proves nothing about who sent it. HMAC fixes that by mixing a shared secret key into the hashing process in a specific, cryptographically sound way (not just concatenating the key and message, which turns out to have exploitable weaknesses). The result: only someone who knows the secret key could have produced that exact HMAC for that exact message. That's what makes it useful for authentication, not just integrity.
Where you'll actually run into this
- Webhook signature verification — Stripe, GitHub, Shopify and most other webhook providers sign their payloads with HMAC-SHA256 and send the signature in a header. Your endpoint recomputes the HMAC over the raw request body with the shared secret and compares it against that header — if they don't match, the request didn't actually come from who it claims to.
- API request signing — AWS's Signature Version 4 process, and plenty of other API auth schemes, use HMAC chains to prove a request came from someone holding the secret key without ever sending that key over the wire.
- JWTs signed with HS256 — the "HS" stands for HMAC-SHA. Same underlying mechanism as everything else here, just applied to a token instead of an arbitrary message.
The comparison mistake that actually matters
When you verify an HMAC in your own code, compare it using a constant-time comparison function, not a plain string equality check like === or ==. A naive comparison can leak timing information about how many leading bytes matched, which — while a genuinely difficult attack to pull off in practice — is exactly the kind of thing that shouldn't be left as a foreseeable weakness when a constant-time comparison function is one line away in virtually every language's standard library.