HMAC, short for hash-based message authentication code, is a construct defined in RFC 2104 that combines a cryptographic hash function with a secret key to produce a fixed-length tag proving both the integrity and the authenticity of a message. Unlike a plain hash, which anyone can recompute and therefore cannot prove who sent a message, HMAC binds the hash to a shared secret so that only parties holding the key can generate or verify a valid tag. If you're asking what is HMAC in practical terms: it's the mechanism that lets a server confirm an API request, webhook payload, or JWT wasn't altered in transit and actually came from a party that knows the secret key. Formalized by Bellare, Canetti, and Krawczyk in 1996, HMAC is now embedded in TLS, IPsec, OAuth signing, AWS request signing, and countless webhook implementations across the software supply chain.
What Is HMAC and Why Was It Created?
HMAC exists because naive attempts to turn a hash function into an authentication tool are broken in subtle ways. Early designs simply concatenated a secret key with a message and hashed the result — for example, H(key || message). That scheme falls apart against a length-extension attack: for hash functions like MD5 or SHA-1/SHA-256 that use the Merkle-Damgård construction, an attacker who knows H(key || message) and the length of the key can compute H(key || message || extra) for attacker-chosen extra, without ever knowing the key itself. Bellare, Canetti, and Krawczyk designed HMAC to close that hole by nesting the hash function twice around the key: HMAC(K, m) = H((K' ⊕ opad) || H((K' ⊕ ipad) || m)), where K' is the key padded to the hash's block size and ipad/opad are fixed constants. This nested structure gives HMAC a formal security proof — it's provably a secure pseudorandom function as long as the underlying hash is reasonably well-behaved — which is why it survived even after collision attacks weakened MD5 and SHA-1 for other purposes.
How Does HMAC-SHA256 Work Under the Hood?
HMAC-SHA256 works by running SHA-256 twice, once over an "inner" key-padded message and once over an "outer" key-padded digest, to produce a 256-bit (32-byte) authentication tag. To walk through HMAC-SHA256 explained at the byte level: SHA-256 has a 64-byte internal block size, so the key is first padded (or, if longer than 64 bytes, hashed down) to exactly 64 bytes. That padded key is XORed with the ipad constant (0x36 repeated), concatenated with the message, and hashed — producing an inner digest. The padded key is then XORed with the opad constant (0x5c repeated), concatenated with that inner digest, and hashed again to produce the final tag. A concrete real-world instance: AWS Signature Version 4, used to authenticate every request to S3, EC2, and other AWS APIs, derives a signing key through four chained HMAC-SHA256 operations (date, region, service, and a fixed "aws4_request" string) and then HMACs the canonical request string with that derived key. Change one header or one byte of the request body, and the resulting signature no longer matches — AWS rejects the call.
How Is HMAC Different From a Digital Signature?
HMAC relies on a single symmetric secret shared by both parties, while a digital signature relies on an asymmetric key pair where only the signer holds the private key. That distinction is the crux of the HMAC vs digital signature comparison developers run into constantly when choosing how to authenticate data. With HMAC, anyone who can verify a tag also possesses the key needed to forge one, which means HMAC cannot provide non-repudiation — you can't later prove to a third party which side actually generated the tag. Digital signatures (RSA-PSS, ECDSA, Ed25519) solve that by letting the verifier hold only a public key, so the signer can be held provably accountable, which is why code-signing certificates and Sigstore/cosign artifact signatures use asymmetric signatures rather than HMAC. The trade-off is speed and simplicity: HMAC-SHA256 is orders of magnitude cheaper to compute and verify than RSA or ECDSA operations, which is exactly why high-throughput systems like webhook delivery and API request signing default to HMAC when both endpoints already share a provisioned secret.
Where Do Real Systems Actually Use HMAC?
Real systems use HMAC anywhere two parties share a secret in advance and need fast, low-overhead proof that a message is unmodified and genuine. Stripe, GitHub, Slack, and most other webhook providers sign every outbound payload with HMAC-SHA256 over the raw request body, sending the resulting tag in a header (GitHub uses X-Hub-Signature-256); the receiving server recomputes the HMAC with its copy of the webhook secret and compares it to the header before trusting the payload. JSON Web Tokens signed with the HS256 algorithm use HMAC-SHA256 over the base64url-encoded header and claims. TLS cipher suites that predate AEAD ciphers (like the older TLS_RSA_WITH_AES_128_CBC_SHA256 suites) used HMAC to authenticate each encrypted record. And package managers and artifact stores frequently use HMAC-based checksums internally to verify that a cached or mirrored artifact matches what was originally published, which is directly relevant to supply chain integrity checks on build artifacts and container layers.
How Does HMAC Provide Message Integrity Verification?
HMAC provides message integrity verification because the underlying hash function is designed so that flipping even a single bit of the input produces a completely different, unpredictable digest — the avalanche effect — and without the secret key, an attacker cannot compute a matching tag for a tampered message. Consider a webhook receiver validating a payment notification: it takes the raw request body, computes HMAC-SHA256(shared_secret, raw_body), and compares the result to the signature header using a constant-time comparison function (never a plain ==, which can leak timing information byte by byte). If an attacker intercepts the request and changes the amount field from $10 to $10,000, the recomputed HMAC won't match the original signature, and the server rejects the request before it ever reaches business logic. Note that HMAC alone only proves integrity and authenticity of the message content — it does not, by itself, prevent replay of a previously valid, unmodified request. Robust implementations pair HMAC with a timestamp or nonce included in the signed payload so that a captured signature/message pair can't simply be resent later.
Can HMAC Be Broken or Misused?
HMAC itself has no known practical breaks when implemented correctly with a modern hash function, but it is frequently undermined by implementation mistakes rather than cryptographic weaknesses. The most common failure is a weak or leaked secret key: if a webhook secret is committed to a public repository, hardcoded in a mobile app binary, or reused across environments, HMAC's guarantees evaporate because the attacker simply has the key. Using non-constant-time comparison to check tags opens the door to timing attacks that let an attacker recover a valid signature byte by byte. Choosing a deprecated hash function underneath — HMAC-MD5 or HMAC-SHA1 — doesn't collapse as badly as those hashes do in other contexts (HMAC's security proof degrades more gracefully than plain hashing under collision attacks), but it's still best practice to move to HMAC-SHA256 or HMAC-SHA3-256. Finally, key reuse across unrelated purposes — using the same secret for webhook signing and session tokens, for instance — means a compromise in one context cascades into another. Each of these is an operational or configuration failure, which is exactly the category of risk that shows up repeatedly in software supply chain incidents.
How Safeguard Helps
Safeguard treats HMAC usage as a first-class signal in software supply chain security rather than an implementation detail buried in application code. Our scanning surfaces hardcoded or leaked HMAC secrets across source repositories, CI/CD configuration, and container images before they reach production, and flags webhook and API integrations that skip signature verification entirely or use deprecated hash algorithms underneath HMAC. In build and release pipelines, Safeguard verifies HMAC- and signature-based integrity checks on dependencies, artifacts, and package metadata, so a tampered package can't silently pass through a mirror or cache. And because HMAC secret sprawl is a common root cause of authentication bypass in CI/CD systems, Safeguard maps where each shared secret is used across your environment, helping teams rotate keys, enforce scoping, and eliminate reuse before it becomes an incident — turning a cryptographic primitive most teams treat as boilerplate into a measurable, auditable part of your supply chain security posture.