Back to Technical Mode
HMAC Request Signing
HMAC (Hash-based Message Authentication Code) combines a shared secret with the request contents to produce a signature that changes completely if even one character of the request changes.
The signature covers the method, path, body, and a timestamp — not just the body
Changing a single character anywhere in the signed content invalidates the whole signature
The shared secret never travels in the request — only the resulting signature does
This defeats tampering even over a channel where TLS has already been stripped or intercepted
Want this flow explained in detail as it plays?
POST/api/orders
X-Timestamp: 1735689600
X-Signature (original, sent by the real client):
Body (tamper with it — the signature above won't update, because an attacker doesn't know the shared secret)
Loading...
Defense in depth
- Server recomputes HMAC-SHA256(method + path + body + timestamp, shared_secret) and compares to X-Signature
- Any mismatch, however small the change, is rejected with 403
- The timestamp is also checked for freshness so an old signed request can't be resubmitted indefinitely
Signing vs. Verification
import { createHmac } from "crypto";
function sign(method: string, path: string, body: string, ts: string, secret: string) {
return createHmac("sha256", secret)
.update(`${method}${path}${body}${ts}`)
.digest("hex");
}