Protecting Requests with HMAC (Including Timestamps & Nonces)
Most APIs use API keys or OAuth tokens, but those alone don’t prevent certain types of attacks—especially replay attacks where a captured valid request is resent later. This article covers how to protect your requests using HMAC signing, timestamps, and nonces.
What is HMAC?
HMAC (Hash-based Message Authentication Code) is a way to prove:
- Integrity: The message hasn’t been modified.
- Authenticity: The sender knows a secret key.
How it works (high level):
-
Both client and server share a secret key.
-
The client creates a signature:
signature = HMAC(secret, message)
-
The server recomputes and compares it:
expected_signature = HMAC(secret, message)
-
If they match → the request is valid.
Learn HMAC basics: Watch this short video
Replay Attacks: The Missing Piece
Even with HMAC, attackers can capture a valid signed request and send it again (e.g., reusing a payment request).
Solution: Add Timestamps and Nonces
1. Timestamp
Include a header:
X-Timestamp: 2025-07-31T20:00:00Z
Server checks:
- Is it within a window? (e.g., ±5 minutes)
- If too old or too far in the future → reject.
Effect: stops long-term replay (hours or days later).
2. Nonce
A nonce is a one-time random string:
X-Nonce: 123e4567-e89b-12d3-a456-426614174000
Server keeps a short-lived cache (e.g., Redis) of (api_key, nonce)
:
- If it’s reused → reject.
Effect: stops short-term replay (identical requests within that window).
*The Process**
Client signs a canonical string:
POST
/api/v1/payment
SHA256(body)
2025-07-31T20:00:00Z
123e4567-e89b-12d3-a456-426614174000
Generates a signature:
signature = HMAC_SHA256(secret, canonical_string)
Adds headers:
X-Timestamp, X-Nonce, X-Signature
Send Request.
Server checks:
- Timestamp is recent.
- Nonce not used before.
- Signature matches.
Why Both Timestamp and Nonce?
-
Timestamp alone: stops old replays, but not fast duplicates.
-
Nonce alone: prevents duplicates but requires unbounded storage -- Moore's law isn't that good
-
Together:
- Timestamp bounds nonce storage (only needed for the time window)
- Nonce ensures uniqueness inside that window.
Key Takeaway
HMAC ensures the request is authentic. Timestamps & nonces ensure it’s also fresh and unique.
Related: Cheap De‑Dup with Hash + TTL
Replay protection (HMAC + timestamp + nonce) proves the request is fresh and authentic. If you also want to suppress accidental duplicates inside a short window, add a hash + TTL gate: compute a stable hash of the canonical request and SETNX
it in Redis with a TTL. If it already exists, drop it. Different goal, complementary tool.