How to Generate an HMAC-SHA-256 Signature
How do I generate an HMAC-SHA-256 signature?
Pick the tool for your stack. In Node.js use crypto.createHmac("sha256", secret).update(message).digest("hex"). In Python use hmac.new(key, msg, hashlib.sha256).hexdigest(). On the command line use openssl dgst -sha256 -hmac <secret>. All three produce the same value for the same message and key.
The inputs
An HMAC signature needs exactly three things: the message, the shared secret key, and the hash algorithm, SHA-256 here. The output format matters too: hex is 64 characters and base64 is shorter. The receiver must use the same format you do.
Node.js
const crypto = require("crypto"); const sig = crypto.createHmac("sha256", secret).update(message).digest("hex");. Swap "hex" for "base64" when the receiver expects base64.
Python
import hashlib, hmac; sig = hmac.new(key.encode(), msg.encode(), hashlib.sha256).hexdigest(). The hmac module ships with Python, so there is nothing to install.
OpenSSL on the command line
printf '%s' "$message" | openssl dgst -sha256 -hmac "$secret" -hex prints the hex signature. Append -binary | base64 for base64 output. This is convenient in shell scripts and CI pipelines.
A worked example
With the message The quick brown fox jumps over the lazy dog and the key key, HMAC-SHA-256 in hex is f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8. Use a known vector like this to confirm a library is producing correct output.
Verify with constant time
Never compare signatures with a plain equality check. Use timingSafeEqual in Node or hmac.compare_digest in Python so the comparison time does not leak information about the key.
Try it in your browser with our HMAC Generator. No upload, no server.
Open HMAC Generator →FAQ
Is hex or base64 better?
Both are fine as long as sender and receiver agree. Hex is longer and convenient for logs, while base64 is more compact for headers.
Can I generate HMAC without a library?
Yes, but do not. OpenSSL covers it from the command line, and Node.js and Python have it built in. Hand-rolled HMAC is a common source of subtle bugs.
How do I verify an incoming signature?
Recompute HMAC with your secret key and the exact received message, then compare in constant time with timingSafeEqual or compare_digest.