Cryptography

HMAC

Hash-based Message Authentication Code

A keyed MAC built from a hash function (RFC 2104, FIPS 198-1) that proves a message came from a key holder and was not altered.

HMAC computes H((K xor opad) || H((K xor ipad) || message)). The nested construction avoids the length-extension weakness of naive H(key || message) with SHA-256. Anyone holding the shared key can create or verify the tag; nobody else can forge one.

It is everywhere symmetric integrity is needed: webhook signatures (Stripe, GitHub), AWS SigV4 request signing, HS256 JWTs, TOTP codes, HKDF, and keyed hashing of identifiers for pseudonymisation or password peppers.

The classic bug is comparing tags with ==, which leaks timing; use a constant-time compare. Others: signing a non-canonical representation (parsed JSON rather than the raw body), no timestamp so captured requests replay forever, and sharing one key across purposes. HMAC gives no non-repudiation, since both sides hold the key.

Verifying a webhook signaturets
import { createHmac, timingSafeEqual } from "node:crypto";

const expected = createHmac("sha256", secret).update(rawBody).digest();
const given = Buffer.from(signatureHex, "hex");
const ok = given.length === expected.length && timingSafeEqual(given, expected);

Learn it properly

Compared

Also used in

Related terms