✍️ HMAC Signature Generator
Compute HMAC signatures in your browser — no server, no data leaves your machine.
HMAC Signatures: The Foundation of Webhook and API Request Verification
Every developer building integrations eventually hits a moment of recognition: an inbound HTTP request arrives at your endpoint, and you have no reliable way to know whether it actually came from the claimed sender or whether a man-in-the-middle tampered with the payload in transit. TLS prevents eavesdropping, but it does nothing to prove the body of a POST request was authored by the holder of a specific secret. That problem is exactly what HMAC — Hash-based Message Authentication Code — was designed to solve.
What HMAC Actually Computes
HMAC is defined in RFC 2104 and works by combining a secret key with your message before hashing, in a specific two-pass construction. The algorithm first XORs the key with an inner padding constant, appends the message, and hashes that. It then XORs the original key with an outer padding constant, appends the result of the first hash, and hashes again. The final digest is the HMAC.
This two-pass structure is deliberate. A naive approach — simply prepending the key to the message and hashing once — is vulnerable to length extension attacks when used with MD5 or SHA-1 based hash functions. Stripe, GitHub, Shopify, Twilio, and virtually every other SaaS platform that sends webhooks chose HMAC-SHA-256 precisely because it is immune to this class of attack while remaining fast enough to compute on every incoming request.
SHA-256 vs SHA-512 vs SHA-1: Which Should You Use?
SHA-1 is included here for compatibility with legacy systems only. Its underlying compression function has known collision vulnerabilities (the SHAttered attack demonstrated practical SHA-1 collisions in 2017). For new integrations, never choose HMAC-SHA-1 unless a third-party system forces your hand.
HMAC-SHA-256 is the industry standard. The digest is 32 bytes (256 bits), which when hex-encoded produces a 64-character string. This is what you see in GitHub's X-Hub-Signature-256 header, Stripe's Stripe-Signature, and Slack's X-Slack-Signature. The security margin is comfortable for all foreseeable uses — breaking HMAC-SHA-256 would require computing effort proportional to 2^256, which is beyond any realistic attack budget.
HMAC-SHA-512 doubles the output to 64 bytes (512 bits) and 128 hex characters. The extra security margin is not meaningful in practice for authentication codes — 256 bits is already more than sufficient. SHA-512 can actually be faster than SHA-256 on 64-bit CPUs due to architectural differences in how word sizes align with the hash internals, so choose it when you need to match a specific platform requirement, not for abstract security reasons.
Hex vs Base64 Output: When Each Makes Sense
The underlying signature is just a sequence of bytes. How you encode those bytes into a printable string depends on where the signature is going. Hex encoding (base-16) maps every byte to two hexadecimal characters, producing a longer string that is entirely lowercase ASCII alphanumeric. It is universally safe to embed in HTTP headers, JSON strings, query parameters, and log files without escaping.
Base64 encoding maps three bytes to four printable characters, producing a roughly 33% shorter string. However, standard Base64 includes +, /, and trailing = padding characters, which require URL-encoding in query strings. Many APIs use Base64 to minimize header size. The Authorization: Bearer token pattern and AWS Signature Version 4 both rely on Base64 to keep signed strings compact. When verifying, always confirm whether the receiving system expects standard Base64 or URL-safe Base64 (which replaces + with - and / with _).
The Secret Key Format Question
This generator supports three key input formats, which eliminates a common source of bugs. When a webhook provider gives you a signing secret like whsec_abc123..., the prefix is metadata, not part of the key. Some providers supply keys that are already Base64-encoded bytes, meaning you must decode them before passing to the HMAC function. Others give you the raw UTF-8 string.
AWS in particular uses hex-encoded intermediate keys during the SigV4 signing process, where the key for each subsequent step is derived by computing HMAC over the previous step's output. If you pass hex-encoded bytes as a UTF-8 string, you will compute a completely different HMAC — a mistake that generates hours of debugging frustration. Using the Hex key format option in this tool lets you paste the hex-encoded key directly and get the same result as a server-side implementation that decodes first.
Timing-Safe Comparison: The Final Piece
Computing the HMAC is only half the job on the receiving end. When your server verifies an incoming webhook signature, you must compare the expected HMAC against the received signature using a constant-time comparison function. A standard string equality check short-circuits as soon as it finds a differing character, leaking information about how many leading bytes match. An attacker who can make thousands of requests can use this timing oracle to forge a valid signature one byte at a time — a timing side-channel attack.
In Node.js, use crypto.timingSafeEqual(). In Python, use hmac.compare_digest(). In Go, use subtle.ConstantTimeCompare(). Before calling any of these, ensure both sides are the same length (different lengths immediately indicate mismatch without needing byte-by-byte comparison, so length disclosure alone is not exploitable). This tool is designed for generating test signatures to paste into your API client — the comparison logic lives server-side and must always use these constant-time primitives.
Practical Workflow: Testing Stripe Webhooks Locally
Stripe computes its webhook signature by concatenating the Unix timestamp, a literal dot, and the raw request body, then signing that concatenated string with HMAC-SHA-256. The header format is t=<timestamp>,v1=<hex_signature>. To reproduce this manually: take your test payload JSON, prepend the timestamp and a dot, paste the result into the Message field, paste your Stripe webhook secret into the Key field (as UTF-8), select SHA-256 and hex output, and generate. The result should match the v1 component of the Stripe-Signature header exactly. This generator runs entirely in your browser using the Web Crypto API — your secret key and payload never touch a network request.
Browser Security: Why Local Computation Matters
Several online HMAC tools send your inputs to a server to compute the hash. Sending a secret signing key to a third-party server is a security failure — any server-side tool that accepts your signing secret has access to it, can log it, and could use it to forge signatures on your behalf indefinitely. The Web Crypto API (the SubtleCrypto interface accessed via crypto.subtle) provides native HMAC implementations in every modern browser, so there is no reason to ever send signing keys over the network for this purpose. Everything computed here stays on your machine.