HMAC (Hash-based Message Authentication Code) is a construction that combines a cryptographic hash function with a secret key to produce a tag proving both that a message wasn't altered (integrity) and that it came from someone holding the key (authenticity). It's specified in RFC 2104, and works with any underlying hash — HMAC-SHA256 and HMAC-SHA1 are the common names for HMAC built on SHA-256 or SHA-1.
A plain hash of a message proves only integrity: anyone can recompute SHA256(message) and compare it, so it says nothing about who produced it. HMAC fixes this by mixing a shared secret key into the hash computation itself, roughly: HMAC(K, m) = H((K' ⊕ opad) || H((K' ⊕ ipad) || m)), where K' is the key padded to the hash's block size and opad/ipad are fixed constants. The result is a tag that only someone with the same key K can reproduce or verify — an attacker who can see the message and its HMAC still can't forge a valid HMAC for a different message without the key.
This is exactly the mechanism behind a JWT's HS256 signature, and it's the standard way services like Stripe and GitHub let webhook receivers verify that a payload really came from them: the sender computes an HMAC-SHA256 over the raw request body using a shared secret and sends it in a header; the receiver recomputes it locally and compares.
Example:
HMAC-SHA256("The quick brown fox jumps over the lazy dog", key="key")
= f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8
== string comparison can leak timing information; use a constant-time comparison function to avoid timing attacks.HS256).HS256 variant) to prove the token wasn't tampered with.