Answer: HMAC = a hash + a secret key. HMAC-SHA256 with key key over The quick brown fox jumps over the lazy dog = f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8. Unlike a plain SHA-256 digest, nobody can produce that string without the key β€” which is why webhooks (Stripe, GitHub), AWS SigV4, and JWT HS256 all use HMAC. This tool uses the browser's native WebCrypto (crypto.subtle); your key never leaves the page.

Message & Key

HMAC-SHA256 (Hex)
computing…
Hexadecimal
β€”
Base64
β€”
Advertisement

HMAC Algorithm Reference

AlgorithmOutput sizeHex lengthCommon uses
HMAC-SHA120 bytes40 charsLegacy systems, old JWTs (HS1), some API OTP schemes
HMAC-SHA25632 bytes64 charsStripe/GitHub webhooks, JWT HS256, AWS SigV4, most new APIs
HMAC-SHA38448 bytes96 charsTLS cipher suites, higher-assurance API signing
HMAC-SHA51264 bytes128 charsJWT HS512, interbank/payment signing, system-to-system auth

SHA-256 remains the default choice for new designs; SHA-1 HMACs are still considered safe against collision attacks in the HMAC construction, but nothing new should adopt them. Longer variants add output size, not meaningful extra security against brute force.

Known-Answer Test Vectors

AlgorithmKeyMessageExpected HMAC (hex)
HMAC-SHA1keyThe quick brown fox jumps over the lazy dogde7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9
HMAC-SHA256keyThe quick brown fox jumps over the lazy dogf7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8
HMAC-SHA384keyThe quick brown fox jumps over the lazy dogd7f4727e2c0b39ae0f1e40cc96f60242d5b7801841cea6fc592c5d3e1ae50700582a96cf35e1e554995fe4e03381c237
HMAC-SHA512keyThe quick brown fox jumps over the lazy dogb42af09057bac1e2d41708e48a902e09b5ff7f12ab428a4fe86653c73dd248fb82f948a549f7b791a5b41915ee4d1ec3935357e4e2317250d0372afa2ebeeb3a

Every row above is preloaded into the calculator defaults β€” switch algorithms and the output should match the table exactly. If it does, your HMAC verification code is wired correctly.

How the HMAC Generator Works

This page signs with crypto.subtle, the WebCrypto API built into every modern browser. No HMAC library is loaded, no request carries your key or message, and the computation is constant-work regardless of input size. That's the same primitive Node and Python call into under the hood.

How to use it

Paste the message, type the secret, pick an algorithm, and both hex and Base64 outputs appear as you type. Switch the key encoding to Hex when your secret arrives as hex bytes β€” common with payment gateways β€” and the bytes are used exactly as given. The default message and key reproduce the classic test vector, so you can confirm your own verification code against a known answer before trusting it with real traffic. For webhook debugging, compare the computed hex against the signature header a service sent you (see the HMAC explainer for header formats and timing-attack-safe comparison).

A worked example

Stripe signs webhooks as Stripe-Signature: t=timestamp,v1=hex, where v1 is HMAC-SHA256 of timestamp + "." + raw_body using your endpoint secret. To check one by hand, paste the secret as the key, build 1735689600.{...json...} as the message, and compare with the v1 value. A match proves the request came from someone holding your secret key β€” a mismatch means a forged or mis-ordered payload.

The tool's default state shows the same idea with friendlier numbers: message The quick brown fox jumps over the lazy dog, key key, HMAC-SHA256 β†’ f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8, or 97yD9DBThCSxMpjmqm+xQ+9NWaFJRhdZl0edvC0aPNg= in Base64. Same inputs, same key, always the same output β€” but no key, no way to reproduce it.

Compute HMAC in your own code

# Node.js
const hmac = crypto.createHmac('sha256', 'key')
  .update('The quick brown fox jumps over the lazy dog')
  .digest('hex');

# Python
import hmac, hashlib
hmac.new(b'key', b'The quick brown fox jumps over the lazy dog',
         hashlib.sha256).hexdigest()

# Browser (what this page does)
const key = await crypto.subtle.importKey(
  'raw', new TextEncoder().encode('key'),
  { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
const sig = await crypto.subtle.sign('HMAC', key,
  new TextEncoder().encode(message));
const hex = [...new Uint8Array(sig)]
  .map(b => b.toString(16).padStart(2, '0')).join('');

All three produce the same 64 hex characters. When verifying incoming signatures, compare digests with a constant-time equality function (crypto.timingSafeEqual in Node, hmac.compare_digest in Python) rather than ===.

Frequently Asked Questions

What is an HMAC?

An HMAC (hash-based message authentication code) is a signature computed from a message AND a secret key. Anyone can recompute a plain SHA-256 digest, but only someone holding the key can produce or verify the matching HMAC. That key is what turns a hash into proof that a message came from you and wasn't tampered with.

How do I compute HMAC-SHA256?

Take your message bytes and key, and run them through the HMAC construction with SHA-256 as the inner hash. In Node: crypto.createHmac('sha256', key).update(message).digest('hex'). In Python: hmac.new(key, message.encode(), hashlib.sha256).hexdigest(). In the browser, WebCrypto's crypto.subtle.sign with an imported HMAC key does it natively β€” no libraries.

What is HMAC-SHA256 of a known test vector?

HMAC-SHA256 with key "key" over the message "The quick brown fox jumps over the lazy dog" equals f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8 in hex. RFC 4231 and RFC 2202 publish more test vectors for every SHA family size.

Where is HMAC used in practice?

Everywhere signatures are needed without public-key machinery: Stripe and GitHub webhook signatures, AWS Signature Version 4, JWTs signed with HS256, TLS record protection, and cookie session integrity. If a service hands you a signing secret, HMAC is almost certainly behind it.

HMAC vs SHA-256: what's the difference?

SHA-256 alone is a digest: unkeyed, and computable by anyone. HMAC-SHA256 folds a secret key into the hashing so the output depends on both the message and the key. Use a plain hash for checksums and file integrity; use HMAC when you need to prove authenticity.

Does my key or message leave the browser?

No. This page computes HMACs with crypto.subtle, the browser's built-in WebCrypto implementation. Everything runs locally in JavaScript; there is no network call carrying your key or message. That makes it safe for testing internal webhook secrets, though production secrets should still never be pasted anywhere casually.

Advertisement