APIs and webhooks depend heavily on HMAC (Hash-based Message Authentication Code) to ensure that every request you receive is authentic and unaltered.
Without signature verification, your application could be vulnerable to spoofing, data tampering, or replay attacks.
In this guide, you’ll learn:
- What an HMAC signature is and how it works
- How to generate and verify HMAC signatures in Python, Node.js, and Go
- Common mistakes developers make and how to fix them
- How to test your HMACs using a free online tool: Authgear’s HMAC Signature Generator & Verifier
What Is an HMAC Signature?
An HMAC (Hash-based Message Authentication Code) is a message authentication code created by combining a cryptographic hash function (like SHA256) with a secret key.
It ensures two critical properties:
- Integrity: The message hasn’t been modified in transit.
- Authenticity: The message came from a trusted source that knows the secret key.
The formula is conceptually simple:
HMAC = hash(secret_key + message)
Both the sender and receiver use the same secret key. If both sides compute the same HMAC value, the message is valid.
Why Use HMAC for APIs?
When APIs accept requests — for example, POST /payment
— you need to verify that the request came from a trusted client.
HMAC-based signing ensures that only senders with the correct secret can generate a valid signature.
Typical flow:
- The client computes an HMAC for the request body.
- It sends the request with a header such as
X-Signature: <hmac_value>
. - The server recalculates the HMAC and compares the two.
- If they match, the request is trusted and processed.
Many large platforms like Stripe, Shopify, GitHub, AWS, and Slack use HMAC for webhook verification and secure request signing.
How HMAC Works Step by Step
- Combine the secret and message.
- Hash the combination using a cryptographic algorithm (e.g., SHA256).
- Compare both signatures to confirm authenticity.
- Choose the right algorithm:
- HMAC-SHA256 (recommended for most cases)
- HMAC-SHA1 (legacy)
- HMAC-SHA512 (for high-security applications)
Generate and Verify HMAC in Python
Python’s hmac
and hashlib
libraries make generating HMACs straightforward.
import hmac
import hashlib
message = b"Hello from Authgear"
secret = b"mysecretkey"
signature = hmac.new(secret, message, hashlib.sha256).hexdigest()
print("Generated HMAC:", signature)
expected_signature = "your_received_signature_here"
is_valid = hmac.compare_digest(signature, expected_signature)
print("Signature valid?", is_valid)
Always use compare_digest()
for verification — it prevents timing attacks.You can try generating your own message and signature using Authgear’s free HMAC Signature Generator & Verifier tool.
Generate and Verify HMAC in Node.js
Node’s built-in crypto library provides similar functionality.
const crypto = require('crypto');
const message = 'Hello from Authgear';
const secret = 'mysecretkey';
// Generate HMAC
const signature = crypto
.createHmac('sha256', secret)
.update(message)
.digest('hex');
console.log('Generated HMAC:', signature);
// Verify HMAC securely
const received = 'your_received_signature_here';
const isValid = crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(received)
);
console.log('Signature valid?', isValid);
The timingSafeEqual
function avoids timing-based comparison leaks.
Generate and Verify HMAC in Go
Go’s crypto/hmac
package provides a clean interface for HMAC generation and verification.
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
)
func main() {
message := []byte("Hello from Authgear")
secret := []byte("mysecretkey")
mac := hmac.New(sha256.New, secret)
mac.Write(message)
expectedMAC := mac.Sum(nil)
fmt.Printf("Generated HMAC: %s\n", hex.EncodeToString(expectedMAC))
// Verification example
receivedMAC, _ := hex.DecodeString("your_received_signature_here")
valid := hmac.Equal(expectedMAC, receivedMAC)
fmt.Println("Signature valid?", valid)
}
Real-World Example: Signing API Requests
Here’s an example of how HMAC signatures are used to authenticate API requests.
Client (Sender):
import requests, hmac, hashlib
url = "https://api.yourserver.com/webhook"
data = '{"order_id": "12345"}'
secret = b"mysecretkey"
signature = hmac.new(secret, data.encode('utf-8'), hashlib.sha256).hexdigest()
headers = {"X-Signature": signature}
requests.post(url, headers=headers, data=data)
Server (Receiver):
import hmac, hashlib
from flask import Flask, request
app = Flask(__name__)
SECRET = b"mysecretkey"
@app.route("/webhook", methods=["POST"])
def webhook():
payload = request.data
received_sig = request.headers.get("X-Signature")
computed_sig = hmac.new(SECRET, payload, hashlib.sha256).hexdigest()
if hmac.compare_digest(received_sig, computed_sig):
return "Verified!", 200
else:
return "Invalid signature", 403
This ensures only authorized senders can submit valid requests.
Common Mistakes and How to Fix Them
Choosing the Right Hash Algorithm
Testing Your HMAC Online
You can instantly generate and verify your HMAC signatures using Authgear’s free online tool: HMAC Signature Generator & Verifier
The tool supports:
- Algorithms: SHA-1, SHA-256, SHA-512
- Generate and Verify modes
- Copy-to-clipboard output
- Real-time hex output
It’s ideal for quickly testing your request signatures or debugging mismatched API keys.
Frequently Asked Questions
What algorithm does HMAC use?
HMAC can use SHA256, SHA1, or SHA512. SHA256 is most commonly used for APIs because it’s secure and widely supported.
Can I use HMAC for API authentication?
Yes. Platforms like Stripe, AWS, and GitHub use HMAC to sign API requests and webhooks.
What’s the difference between HMAC and hashing?
Hashing only ensures data integrity, while HMAC ensures both integrity and authenticity by including a shared secret key.
Is HMAC the same as JWT?
No. JWTs (JSON Web Tokens) can use HMAC algorithms (like HS256), but JWTs also carry payload data for stateless authentication.
What tools can I use to test HMAC online?
Authgear offers a free HMAC Signature Generator & Verifier, plus related tools like a JWK Generator, JWT Decoder, and the complete Authgear Developer Toolkit.