Last updated
What Is HMAC?
HMAC (Hash-based Message Authentication Code) is a cryptographic technique that combines a secret key with a hash function (SHA-256, SHA-512, etc.) to produce a message authentication code. Unlike a plain hash, HMAC requires the secret key to verify — making it impossible to forge without knowing the key. HMAC is used for API authentication, webhook verification, and JWT signatures.
HMAC vs Plain Hash
| Property | SHA-256 | HMAC-SHA256 |
|---|---|---|
| Requires secret key | No | Yes |
| Forgeable without key | Yes | No |
| Verifies integrity | Yes | Yes |
| Verifies authenticity | No | Yes |
| Length extension attack | Vulnerable | Resistant |
HMAC in JavaScript
// Browser Web Crypto API
async function hmacSha256(message, secret) {
const encoder = new TextEncoder();
const keyData = encoder.encode(secret);
const msgData = encoder.encode(message);
const key = await crypto.subtle.importKey(
'raw', keyData,
{ name: 'HMAC', hash: 'SHA-256' },
false, ['sign']
);
const signature = await crypto.subtle.sign('HMAC', key, msgData);
return Array.from(new Uint8Array(signature))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
}
// Verify a webhook signature (e.g., GitHub webhooks)
async function verifyWebhook(payload, signature, secret) {
const expected = 'sha256=' + await hmacSha256(payload, secret);
// Constant-time comparison to prevent timing attacks
return expected.length === signature.length &&
crypto.timingSafeEqual
? crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))
: expected === signature;
}