HMAC
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.
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
- Cryptography you actually needSecEng · Foundations of Security EngineeringFree
- Identity: authentication, authorisation and tokensSecEng · Foundations of Security EngineeringFree
- The bugs that actually shipSecEng · Application Security & DevSecOpsFree
- AEAD and nonce disciplineSecEng · Applied cryptography engineeringFree
- Post-quantum migrationSecEng · Applied cryptography engineeringFree
- Design an API authorisation gatewayHLD · Design problems: Access & identityFree
- Design a bot detection systemHLD · Design problems: fraud & abuseFree
- Design a JWT validatorLLD · Problems: Access controlFree