What Is HMAC and Why APIs Use It
What Is HMAC?
HMAC stands for Hash-based Message Authentication Code. It is a method for proving two things about a message at the same time: that the message has not been changed, and that it comes from someone who holds a shared secret key. A plain hash can show that a message has not changed, because even a small change to the message produces a very different hash. A plain hash cannot show who sent the message, because anyone can compute the hash of a message. HMAC adds a secret key to the process. Only someone who knows the key can produce the correct HMAC for a given message. A receiver who also knows the key can recompute the HMAC and compare it with the one that arrived. If the two values match, the receiver has good reason to believe the message is intact and came from a holder of the key.
Think of HMAC as a tamper-evident seal that only key holders can create. The message itself is not hidden. It travels in readable form, alongside its HMAC. The HMAC is the seal. If anyone changes even one character of the message, the seal will no longer match. If anyone tries to create a new seal without the key, they will produce the wrong value. That combination of integrity and authenticity is why HMAC appears so often in webhooks, application programming interfaces, payment notifications, signed URLs, and other systems where a receiver must decide whether to trust incoming data.
HMAC is not encryption. It does not hide the message. It does not make the message unreadable to someone who intercepts it. If confidentiality is needed, the message must also be sent over an encrypted channel, such as HTTPS, or encrypted separately. HMAC answers a different question: is this message genuine and unchanged? That question matters even when the message itself is not secret.
How HMAC Works in Plain Terms
At a high level, HMAC combines a secret key and a message through a hash function in a specific two-step construction. A hash function takes input of any length and produces a fixed-length output, often shown as hexadecimal characters. HMAC uses that hash function twice, with the key mixed in at both stages, along with padding to make the key the right length for the hash function. The details of the padding and the two passes are defined in the standard, and you do not need to implement them by hand. Every major programming language and cryptography library provides an HMAC function that handles the construction for you.
What matters for using HMAC correctly is the inputs and the output. The inputs are the message and the secret key. The output is a fixed-length authentication code. For HMAC-SHA256, which is one of the most common variants, the output is 256 bits, usually shown as 64 hexadecimal characters. The same message and the same key always produce the same HMAC. Change the message by one character, and the HMAC changes completely. Change the key, and the HMAC also changes completely. That sensitivity is what makes comparison useful. A receiver who recomputes the HMAC with the expected key and gets a different value knows immediately that something does not match.
The choice of hash function matters. HMAC-SHA256 is widely used and widely supported. Older variants based on weaker hash functions are discouraged for new systems. When you set up HMAC, use a modern hash function, use a key that is long enough and generated randomly, and follow the documentation for the service you are integrating with. Different services may specify different details, such as how the message is formatted before hashing, whether the output is hex or base64, and whether the comparison should be done in constant time to avoid timing attacks.
Why APIs Use HMAC
APIs use HMAC because they need a practical way to trust requests and notifications without sending a password with every call. A common pattern is for a service to give each client a secret key when the client signs up. The client then signs each request with that key and sends the signature alongside the request. The server, which also holds the key, recomputes the signature and checks it. If the signatures match, the server processes the request. If they do not match, the server rejects it. The key itself is never sent in the request, which reduces the risk of it being exposed in logs, URLs, or error messages.
Webhooks use the same idea in the opposite direction. A service that sends event notifications signs each notification with a secret shared with the receiver. The receiver verifies the signature before acting on the event. This matters because webhooks are delivered over the public internet to a public endpoint. Without verification, anyone who discovers the endpoint could send fake events. With HMAC verification, fake events fail the check, because the sender does not know the secret. Verification turns an open endpoint into one that only accepts messages from the genuine service.
HMAC is also used for signed URLs, download links, and temporary access tokens. In those cases, the signature proves that the URL was created by someone with the key and has not been altered. If a user tries to change an expiry time or a file name in the URL, the signature will no longer match, and the server will reject the request. That is a simple and effective way to grant limited access without a full login session.
How to Create and Verify an HMAC
Creating and verifying an HMAC follows the same steps on both sides. The only difference is who creates the first value and who checks it. The steps below describe the general workflow. Always follow the specific documentation for the API or service you are using, because the exact message format, encoding, and header names vary.
Step 1: Agree on the Message Format
Decide exactly which bytes will be signed. That might be the raw request body, a timestamp plus the body, a method plus a path plus a body, or another canonical form. Both sides must use exactly the same format, byte for byte. A single extra newline, space, or different ordering will produce a different HMAC and cause verification to fail. If the service provides a canonicalisation rule, follow it precisely.
Step 2: Hold the Secret Key Securely
Store the secret key in a secure location, such as an environment variable or a secrets manager, not in source code, not in a URL, and not in a log file. Only the systems that need to sign or verify should have access to the key. Rotate the key according to the service policy, and revoke it promptly if it may have been exposed.
Step 3: Compute the HMAC on the Sender Side
The sender passes the message and the key to an HMAC function, using the agreed hash function, such as SHA-256. The function returns the authentication code, often encoded as hexadecimal or base64. The sender attaches that code to the message, usually in a header such as a signature header, and sends the message and code together.
Step 4: Recompute and Compare on the Receiver Side
The receiver takes the received message, recomputes the HMAC with the shared key, and compares the recomputed value with the received value. The comparison must be done in a way that does not leak timing information, so use a constant-time comparison function provided by the language or library. If the values match, the message is accepted. If they do not match, it is rejected. Do not act on the message before verification completes, and do not reveal details about why verification failed beyond what the service documentation recommends.
Step 5: Check Freshness and Replay Protection
Many HMAC systems also include a timestamp or a nonce, a one-time value, in the signed message. The receiver checks that the timestamp is recent and that the nonce has not been seen before. This prevents an attacker from capturing a valid signed message and resending it later. HMAC alone proves the message is genuine. It does not prove the message is fresh unless freshness is part of the signed data.
Worked Example: Hello World With a Secret Key
Let us walk through a worked example using a simple message and a simple key, to show the shape of the process. The message is Hello World. The secret key is secret-key. These are illustrative values for learning, not values to use in a real system. In a real system, the key would be long, random, and kept secret, and the message would be formatted exactly as the API specifies.
The sender takes the message Hello World and the key secret-key and passes both to an HMAC function using SHA-256. The output is a 64-character hexadecimal string. Hexadecimal characters are the digits 0 to 9 and the letters a to f. The length is fixed because SHA-256 always produces 256 bits, which is 64 hex characters, no matter how long the message is. A longer message does not produce a longer HMAC. A shorter message does not produce a shorter one. The length stays the same.
The sender then sends the message Hello World together with that 64-character code. The receiver, who also holds the key secret-key, takes the received message Hello World, recomputes the HMAC with the same key, and gets the same 64-character code. Because the two codes match, the receiver accepts the message as genuine and unchanged.
Now consider what happens if the message is altered in transit. Suppose an attacker changes the message to Hello World! by adding an exclamation mark. The receiver recomputes the HMAC for Hello World! with the key secret-key and gets a completely different 64-character code. That code does not match the code that arrived with the original message, so the receiver rejects the message. The receiver does not need to know what the original message was supposed to be. The mismatch alone is enough to show that something is wrong.
Consider also what happens if someone tries to forge a message without the key. Suppose an attacker creates a new message, Hello World, and tries to invent a 64-character code without knowing secret-key. The chance of guessing the correct code is vanishingly small, because the output space is enormous. The receiver recomputes with the real key and gets a different value, so the forgery fails. That is the practical protection HMAC provides: verification, not secrecy of the message, and not secrecy of the HMAC itself.
This example is intentionally simple. In a real integration, the message would often include more than a short phrase. It might include a timestamp, a request path, headers, or the full request body. The principle is the same. Sign the exact bytes, send the signature alongside, and verify before trusting.
Verify, Do Not Trust
The most important habit with HMAC is to verify before you act. Do not trust a webhook because it arrived at your endpoint. Do not trust a request because it looks plausible. Do not trust a signature because it is present. Check it. Recompute it with the key you hold, compare it in constant time, and only then process the message. Verification should happen early, before the message triggers side effects such as creating an order, sending an email, or updating a database.
Also verify that you are using the right key. Many services support multiple keys during rotation, or separate keys for test and production. Using a test key to verify a production message will fail, and using a production key in a test environment is a security risk. Keep environments separate, label keys clearly, and check that the key you are using matches the environment and the service.
If verification fails, treat the message as untrusted. Log the failure without logging the secret key or the full message if it contains sensitive data. Return a generic error. Do not retry the same unverified message automatically, and do not fall back to accepting it because verification is inconvenient. A verification failure is a signal, not a nuisance. It may mean the message was altered, the key is wrong, the message format changed, or the sender is not who it claims to be.
Do Not Share the Key
The security of HMAC depends entirely on the secrecy of the key. Anyone who holds the key can create valid signatures for any message. That is why the key must never be shared in chat, email, screenshots, URLs, client-side code, or public repositories. It must not be committed to version control, even in a private repository that later becomes public. It must not be printed in logs or error messages. If a key may have been exposed, rotate it promptly and update all systems that use it.
Be careful with client-side code. JavaScript that runs in a browser, or code shipped in a mobile app, can be inspected by the user. A secret key placed in such code is not secret. If a browser or app needs to call an API, use a design that does not require the client to hold the secret, such as a server-side proxy or a scoped token with limited permissions. The secret should live on servers you control, not on devices you do not control.
When you rotate a key, update the sender and receiver together, and allow a brief overlap if the service supports it, so that messages signed with the old key and messages signed with the new key are both accepted during the transition. After the transition, disable the old key. Keep a record of which key is active, when it was created, and when it was last rotated, without recording the key value itself in a place that is broadly accessible.
Limitations of HMAC
HMAC proves integrity and authenticity, but it does not provide confidentiality. The message is still readable to anyone who can see it. If the message contains sensitive data, it must be protected separately, for example by using HTTPS. HMAC also does not prove freshness on its own. A valid signature can be replayed unless the signed message includes a timestamp, nonce, or expiry. HMAC also depends on both sides keeping the same key secret. If the key leaks, the protection is lost until the key is rotated. Finally, HMAC requires exact agreement on the message format. A small difference in encoding, ordering, or whitespace will cause verification to fail, which can be frustrating to debug. Clear documentation and test vectors from the service provider help reduce that friction.
Another limitation is key distribution. Both sides must already share the key through a secure channel before HMAC can be used. HMAC does not solve the problem of how to exchange the key safely in the first place. For systems where the parties have no prior relationship, public-key signatures or a key-exchange protocol may be more appropriate. HMAC is strongest when a shared secret already exists and both sides can protect it.
Frequently Asked Questions
Is HMAC the same as a hash?
No. A hash is computed from a message alone. HMAC is computed from a message plus a secret key, using a hash function in a defined construction. A hash shows integrity. HMAC shows integrity and authenticity, because only key holders can produce the correct value.
Does HMAC encrypt the message?
No. HMAC does not hide the message. The message remains readable. HMAC adds a code that lets the receiver verify that the message is genuine and unchanged. Use HTTPS or another encryption layer if the message must be kept confidential.
Why is my HMAC verification failing?
The usual causes are a wrong key, a different message format from the one that was signed, a different encoding of the output, or a timestamp that is outside the accepted window. Check that both sides sign exactly the same bytes, use the same hash function, and use the same output encoding.
Can I share an HMAC key with a client?
Do not place a secret HMAC key in code that runs on a device you do not control, such as browser JavaScript or a mobile app. Anyone who can inspect the code can extract the key and forge signatures. Keep the key on servers you control, and use scoped tokens or a server-side proxy for clients.
Conclusion
HMAC is a way to prove that a message is genuine and unchanged, using a shared secret key and a hash function. The sender signs the message, the receiver recomputes the signature and compares it, and a match means the message can be trusted. In the worked example, Hello World signed with secret-key produces a 64-character hexadecimal code when SHA-256 is used, and any change to the message or the key produces a different code. The rules to remember are simple. Verify before you trust. Do not share the key. Include freshness in the signed data when replay is a concern. With those habits, HMAC becomes a reliable building block for APIs, webhooks, and signed URLs.
Try a Tool
Free, in your browser — no sign-up.
Related Articles
How to Tell If a Link Is Safe Before You Click It
Learn how to tell if a link is safe before you click it. Hover to preview, check the domain, treat shorteners with…
Read article →How to Spot a Phishing Email Before You Click
Learn how to spot a phishing email before you click: check the sender, urgency, and links, hover before clicking, skip attachments, and…
Read article →How to Choose a Password Manager (Without Overthinking It)
Learn how to choose a password manager without overthinking it: vault, master password, 2FA, and a simple setup that keeps every account…
Read article →