An HMAC is a hash that only someone holding the secret key can produce. This page computes HMAC-SHA256 or HMAC-SHA512 with the Web Crypto API — the key is imported via crypto.subtle.importKey, used to sign, and never leaves your browser.
Why not just hash key + message?
The naive construction sha256(key + message) is vulnerable to length extension: SHA-256 processes input block by block and its output is literally its internal state, so an attacker who sees the hash of key+message can keep hashing from that state and forge a valid tag for key+message+padding+anything — without ever knowing the key. HMAC's nested two-pass construction (hash an inner keyed pass, then hash that result under a second keyed pass) closes the hole, which is why hand-rolled MACs are a stock finding in security reviews and HMAC is what standards actually specify.
What happens to your key
HMAC-SHA256 operates on 64-byte blocks (128 for SHA-512). A key shorter than the block is zero-padded; a key longer than the block is hashed down to its digest first. That second rule is observable directly: an 80-byte key and its 32-byte SHA-256 digest produce the identical MAC. The practical consequence: beyond 64 bytes, extra key length buys exactly nothing — a random 32-byte key is the sweet spot. Also note the key here is the UTF-8 bytes of what you type, so secret and Secret are entirely different keys.
Questions people ask
Can someone verify my HMAC without the key?
No. HMAC is symmetric: verification means recomputing the MAC with the same key and comparing, so both sides must share the secret. If you need signatures that anyone can verify without being able to forge, that is asymmetric signing — RSA territory, not HMAC.
Does the HMAC hide my message?
No — the message travels in the clear alongside its MAC. HMAC proves the message was not altered and came from a key holder; it provides no confidentiality. If the content itself is secret, encrypt it (AES) and authenticate it, rather than relying on the MAC to conceal anything.
An HS256 JWT signature is exactly HMAC-SHA256 over the token's first two parts — the JWT decoder on this site shows where this primitive ends up in the wild.