Founder of SumoSign. Writes on electronic signatures, agent-native signing workflows, and evidence-grade contract execution for contract-heavy teams.
What Is HMAC? Hash-Based Message Authentication Codes Explained
HMAC combines a shared secret with a cryptographic hash to prove a message is authentic and unaltered. A practical guide to how HMAC works, when to use it instead of digital signatures, implementation patterns for webhooks and APIs, and the mistakes that break it.
When two systems exchange data over the internet, the hard part is not sending the payload — it is knowing the payload arrived intact and actually came from the party you expect. Hash-based message authentication code, or HMAC, is one of the most widely deployed answers to that problem. It is the mechanism behind signed webhooks, API request authentication, session tokens, and countless server-to-server integrations — including the webhook deliveries that notify your app when an envelope is signed.
This post explains what HMAC is, how it differs from public-key digital signatures, how to implement it correctly, and where it belongs in a modern signing or SaaS stack.
What HMAC is — in plain language
HMAC is a cryptographic authentication technique defined in RFC 2104. It takes a message and a secret key, runs them through a hash function, and produces a fixed-length code — the MAC, or message authentication code. Anyone who holds the same secret can recompute that code and confirm the message has not been changed in transit. Anyone who does not hold the secret cannot forge a valid code, even if they can read the message.
Crucially, HMAC is symmetric: both sender and receiver share one secret key. That is different from RSA or ECDSA digital signatures, where the sender signs with a private key and the receiver verifies with a public key. HMAC is simpler to deploy when both ends are trusted servers under your control, which is why it dominates webhook signing and internal API authentication.
How HMAC works
At a high level, HMAC wraps a standard hash function — today almost always SHA-256 — in a keyed construction that prevents several classes of attack that plain hashing alone would allow. The algorithm pads the secret key, XORs it with inner and outer constants, and hashes the message twice. You do not need to implement this yourself; every mainstream language ships an HMAC primitive. What you do need to agree on with your integration partner are three things:
- The secret key — a high-entropy string known only to the sender and receiver, never transmitted with the message.
- The hash algorithm — SHA-256 is the current baseline; SHA-512 is fine where supported. Avoid MD5 and SHA-1 for new work.
- The exact bytes being signed — which headers, body, timestamps, and delimiters are included in the input string.
The output is a deterministic string of hex or base64 characters. Change a single byte of the message or use the wrong secret, and the recomputed MAC will not match. That property is what makes HMAC useful for integrity checking: tampering is detectable, not recoverable.
A concrete example
Suppose a server sends the message I would like to buy 100 units and signs it with HMAC-SHA256 using a shared secret. The receiver recomputes HMAC-SHA256(secret, message) and compares the result to the value attached to the request. If they match, the receiver knows the message came from someone who holds the secret and was not modified after signing. The original bytes are not recoverable from the MAC — only equality can be tested — which is exactly what authentication requires.
HMAC vs digital signatures
| HMAC | Digital signature (RSA/ECDSA) | |
|---|---|---|
| Key model | Shared secret (symmetric) | Private key signs, public key verifies (asymmetric) |
| Best for | Server-to-server, webhooks, internal APIs | Document signing, certificates, non-repudiation |
| Identity proof | Proves possession of the shared secret | Proves identity tied to a certificate or key pair |
| Secret distribution | Both parties must receive the secret securely | Only the private key must stay secret |
| Typical algorithms | HMAC-SHA256, HMAC-SHA512 | RSA-PSS, ECDSA with SHA-256 |
Neither replaces the other. HMAC answers "did this message come from my integration partner and stay intact?" Digital signatures answer "who signed this document, and can I prove it to a third party?" In e-signature platforms, the signing ceremony and certificate of completion rely on audit evidence and, where required, PKI-backed digital signatures — while webhook notifications that your backend consumes are typically authenticated with HMAC.
How to implement HMAC correctly
Implementation is straightforward in any modern stack, but the details around encoding and comparison matter more than the crypto call itself.
- Generate a long, random secret — at least 32 bytes of entropy — and store it in a secrets manager, not in source code.
- Define the signed payload precisely. Ambiguity here is the most common source of verification failures. Include a version prefix if the format may evolve.
- Attach the MAC in a dedicated header (for example, X-Signature or a vendor-specific header) rather than mixing it into the JSON body.
- Include a timestamp in the signed string and reject requests older than a short window — often five minutes — to limit replay attacks.
- Compare MACs in constant time. Use your language's built-in timing-safe comparison (for example, crypto.timingSafeEqual in Node.js) rather than a plain string equality check.
- Never log the secret or the raw signing input in production.
Webhook signing pattern
The pattern most SaaS APIs use for outbound webhooks looks like this: the provider concatenates a Unix timestamp and the raw request body, computes HMAC-SHA256 with the endpoint's signing secret, and sends both the timestamp and the hex-encoded MAC in a signature header. Your server reads the raw body before JSON parsing, rebuilds the same string, recomputes the MAC, and accepts the event only if the values match and the timestamp is fresh. SumoSign follows this model — deliveries carry an x-sumosign-signature header of the form t=<unix>,v1=<hex>, signed over "<t>.<raw body>" with the whsec_ secret returned when you create the webhook.
When should you use HMAC?
Reach for HMAC whenever two systems that already trust each other need to verify message integrity and origin on every request, and distributing a shared secret is practical.
- Webhook endpoints — confirming lifecycle events (envelope sent, viewed, signed, completed) were emitted by your provider, not injected by an attacker.
- API request signing — authenticating server-to-server calls where OAuth is heavier than necessary.
- Signed URLs and time-limited tokens — ad platforms, CDN edge authentication, and download links often use HMAC over query parameters.
- Inter-service communication inside your own infrastructure — microservices validating internal event buses.
HMAC is less appropriate when you need non-repudiation — proof of who signed something that a third party can verify without access to your secrets — or when secrets cannot be rotated safely across many untrusted parties. For those cases, use public-key signatures and certificates.
Common mistakes to avoid
- Using MD5 or SHA-1 — both are deprecated for security-sensitive use; stick to SHA-256 or stronger.
- Signing parsed JSON instead of the raw body — whitespace and key ordering changes will break verification silently.
- Skipping replay protection — a captured valid request can be resent forever unless timestamps or nonces are checked.
- Reusing the same secret across environments — development, staging, and production should each have distinct secrets.
- Exposing the secret in client-side code — HMAC belongs on servers; browser-held secrets are not secret.
Where SumoSign fits
SumoSign uses HMAC-SHA256 to sign webhook deliveries so your backend can trust envelope lifecycle events before acting on them — updating a CRM, triggering fulfillment, or archiving a signed PDF. The signing secret is returned once when you register the endpoint; store it accordingly. Combined with an append-only audit trail inside the platform, you get authentication at the integration boundary and defensible evidence inside the product.
Build on signed webhooks and evidence-grade signing.
SumoSign delivers HMAC-signed lifecycle events, an append-only audit trail, and exportable certificates of completion — so your integrations and your counsel get the same standard of proof.
Get startedFrequently asked questions
What does HMAC stand for?
HMAC stands for hash-based message authentication code. It is a standard way to authenticate a message using a cryptographic hash function and a shared secret key.
Is HMAC encryption?
No. HMAC does not hide the message — it only produces a code that proves integrity and authenticity to parties who share the secret. If you need confidentiality, encrypt the payload separately (for example, with TLS in transit and AES at rest).
What hash algorithm should I use for HMAC?
HMAC-SHA256 is the practical default in 2026. It is widely supported, well studied, and fast. Use HMAC-SHA512 if your stack and partners already standardize on it; avoid MD5 and SHA-1 for new integrations.
How is HMAC different from a plain hash?
A plain hash like SHA-256(message) is deterministic but not keyed — anyone can compute it. HMAC incorporates a secret so that only holders of that secret can produce or verify the authentication code, which stops attackers from forging valid codes even if they know the hash algorithm.
Why do webhooks use HMAC instead of JWT?
Both work. HMAC is common for webhooks because the provider and your server share one secret, the signed payload is simply the raw HTTP body, and verification is a single hash comparison. JWTs add structure and expiry claims but require parsing and key management that is often unnecessary for one-directional event delivery.
