hmac
The hmac library computes and verifies message authentication codes, most commonly to verify webhook signatures. Keys and messages may be passed as strings (UTF-8 encoded), bytes values, or lists of byte values (as returned by str.encode()).
Available Functions
| Function | Description |
|---|---|
new(key, msg=None, digestmod=None) |
Create an HMAC object. |
digest(key, msg, digestmod) |
One-shot HMAC, returning the raw digest as a bytes value. |
compare_digest(a, b) |
Constant-time string comparison (timing-safe). |
Functions
new(key, msg=None, digestmod=None)
Creates an HMAC object.
Parameters:
key(str,bytes, orlist): Secret key (string encoded as UTF-8, abytesvalue, or a list of byte values).msg(str,bytes, orlist, optional): Initial message data. Default:None.digestmod(stror callable, optional):"sha256"(default),"sha1","md5", or ahashlibconstructor such ashashlib.sha256.
Returns: HMAC: an instance supporting .update(), .hexdigest(), .digest(), and .copy() (see HMAC Object Methods below).
import hmac
sig = hmac.new("secret", "payload", "sha256").hexdigest()
print(sig)digest(key, msg, digestmod)
One-shot HMAC, computing the digest directly without creating a reusable object.
Parameters:
key(str,bytes, orlist): Secret key.msg(str,bytes, orlist): Message data.digestmod(stror callable):"sha256","sha1","md5", or ahashlibconstructor.
Returns: bytes: the raw digest.
import hmac
mac = hmac.digest("secret", "payload", "sha256")compare_digest(a, b)
Compares two strings in constant time, so that timing differences do not leak information about how many leading bytes matched. Use this instead of == when comparing signature values.
Parameters:
a(str): First string.b(str): Second string.
Returns: bool: True if equal, False otherwise.
import hmac
ok = hmac.compare_digest(expected, received)HMAC Object Methods
Objects returned by new() support:
| Method / Field | Description |
|---|---|
.update(data) |
Feed more data into the message. Returns None. |
.hexdigest() |
Return the MAC as a lowercase hex string. |
.digest() |
Return the MAC as a bytes value. |
.copy() |
Return an independent copy of the HMAC object. |
.name |
Algorithm name, e.g. "hmac-sha256". |
.digest_size |
Digest size in bytes. |
.block_size |
Block size in bytes. |
Verifying a Webhook Signature
This is the canonical use case: recomputing the HMAC of a request body with a shared secret and comparing it against the signature header:
import hmac
import hashlib
def verify(body, signature, secret):
expected = "sha256=" + hmac.new(
secret.encode(), body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
body = "the raw request body"
secret = "your-webhook-secret"
good_sig = "sha256=" + hmac.new(secret.encode(), body, "sha256").hexdigest()
print(verify(body, good_sig, secret)) # True
print(verify(body, "sha256=tampered", secret)) # FalseNote: Scriptling does not support parameter type annotations, so write
def verify(body, signature, secret):rather thandef verify(body: bytes, ...) -> bool:.