HMAC Authentication Explained: A Practical Guide for API Developers
You're building an API and Stripe just sent you a webhook. How do you know the payload actually came from Stripe and not from someone spoofing requests? The answer is HMAC, and understanding it will make you a better API developer.
HMAC (Hash-based Message Authentication Code) is everywhere in modern web development — from webhook verification to JWT signing to OAuth 1.0. But many developers treat it as a black box. Let's open it up.
Hashing vs. HMAC: What's the Difference?
A cryptographic hash like SHA-256 takes input and produces a fixed-size output. Anyone can hash the same input and get the same output. That's great for integrity checking (did the file change?), but it doesn't prove anything about who sent the data.
HMAC adds a secret key to the mix. The output depends on both the message and the key. Without the key, you can't reproduce the hash — and that's the whole point.
// Plain hash — anyone can verify
SHA256("hello world") → always the same output
// HMAC — only someone with the secret can verify
HMAC-SHA256("hello world", "my-secret-key") → unique to this keyReal-World Use Case: Webhook Verification
When Stripe, GitHub, or any major service sends you a webhook, they include an HMAC signature in the headers. Here's the flow:
- The sender computes
HMAC(secret, payload) - They include the result in a header like
X-Signature - You compute the same HMAC on your end using your copy of the secret
- If the signatures match, the payload is authentic and unmodified
// Server-side verification (Node.js)
import crypto from 'crypto';
function verifyWebhook(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
// Constant-time comparison to prevent timing attacks
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}Security tip:Always use a constant-time comparison function (like Node's timingSafeEqual) when comparing HMAC signatures. Regular string comparison can leak timing information that lets attackers brute-force your secret one character at a time.
HMAC and JWT: The Connection
JWTs signed with HS256 (HMAC with SHA-256) use HMAC under the hood. The "secret" in your JWT library is the HMAC key. Here's the structure:
// A JWT is three Base64-encoded segments:
header.payload.signature
// The signature segment is:
HMAC-SHA256(
base64(header) + "." + base64(payload),
your-secret
)This is why anyone can read the header and payload of a JWT (they're just Base64), but only you — the holder of the secret — can create or verify the signature.
You can experiment with HMAC signatures for JWTs and API calls using our free HMAC generator — it supports SHA-256, SHA-384, and SHA-512, all computed locally in your browser.
Choosing the Right Hash Function
| Algorithm | Output Size | Best For |
|---|---|---|
| HMAC-SHA256 | 256 bits | Most APIs, JWT signing, webhooks |
| HMAC-SHA384 | 384 bits | Higher security requirements, government applications |
| HMAC-SHA512 | 512 bits | Maximum security, future-proofing |
For most web applications, HMAC-SHA256 is the sweet spot. It's fast, widely supported, and cryptographically secure. SHA-384 and SHA-512 are useful when you need additional security margin or are working in regulated industries.
Key Management: The Hard Part
HMAC is only as secure as your secret key. Here are the rules:
- Use a cryptographically random key — at least 32 bytes for SHA-256
- Never hardcode secrets in your source code. Use environment variables or a secrets manager
- Rotate keys periodically — ideally supporting multiple active keys during rotation windows
- Don't reuse the same key across different services or environments
Wrapping Up
HMAC is one of those foundational concepts that unlocks a lot of practical security patterns. Whether you're verifying webhooks from Stripe, signing JWTs for your authentication system, or building a custom API authentication scheme, the principles are the same: combine a secret key with a message using a cryptographic hash, and you have a verifiable, tamper-proof signature.
Want to generate an HMAC signature right now? Head over to our HMAC Generator and try it with your own message and key — everything runs in your browser, so no secrets ever leave your machine.
Keep Reading
The Developer's Guide to URL-Safe Base64 Encoding
Standard Base64 breaks in URLs. Here's why, how URL-safe Base64 fixes it, and where you'll actually use it.
Read articleUnderstanding HTTP Headers: A Developer's Field Guide
HTTP headers control caching, authentication, content negotiation, and more — including how Basic Auth really works.
Read article