HMAC-based webhook signature generation and verification with timing-safe comparison
pip install philiprehberger-webhook-signatureHMAC-based webhook signature generation and verification with timing-safe comparison.
pip install philiprehberger-webhook-signature
from philiprehberger_webhook_signature import sign
signed = sign(payload='{"event": "order.created"}', secret="whsec_abc123")
print(signed.signature) # HMAC hex digest
print(signed.timestamp) # Unix timestamp
print(signed.to_header()) # "t=1234567890,sha256=abc..."
from philiprehberger_webhook_signature import verify, parse_header
# Parse the signature header
header = request.headers["X-Webhook-Signature"]
signature, timestamp = parse_header(header)
# Verify (raises on failure)
verify(
payload=request.body,
secret="whsec_abc123",
signature=signature,
timestamp=timestamp,
max_age=300.0, # reject signatures older than 5 minutes
)
Use verify_with_rotation for zero-downtime secret rotation. It tries the current secret first and falls back to the previous secret if verification fails:
from philiprehberger_webhook_signature import verify_with_rotation, parse_header
header = request.headers["X-Webhook-Signature"]
signature, timestamp = parse_header(header)
verify_with_rotation(
payload=request.body,
signature=signature,
current_secret="whsec_new_secret",
previous_secret="whsec_old_secret", # optional fallback
tolerance=300,
timestamp=timestamp,
)
from philiprehberger_webhook_signature import (
verify,
SignatureError,
SignatureExpiredError,
SignatureMismatchError,
)
try:
verify(payload, secret, signature, timestamp)
except SignatureExpiredError as e:
print(f"Signature too old: {e.age}s > {e.max_age}s")
except SignatureMismatchError:
print("Invalid signature")
except SignatureError as e:
print(f"Verification failed: {e}")
signed = sign(payload="data", secret="secret", algorithm="sha512")
verify(payload="data", secret="secret", signature=sig, timestamp=ts, algorithm="sha512")
verify(payload, secret, signature, timestamp, max_age=None)
| Function / Class | Description |
|---|---|
sign(payload, secret, algorithm, timestamp) | Generate an HMAC signature for a webhook payload |
verify(payload, secret, signature, timestamp, algorithm, max_age) | Verify a webhook signature with timing-safe comparison |
verify_with_rotation(payload, signature, current_secret, previous_secret, tolerance, algorithm, timestamp) | Verify with key rotation support (tries current then previous secret) |
parse_header(header, prefix) | Parse a signature header string into (signature, timestamp) tuple |
SignedPayload | Signed payload with signature, timestamp, body, and to_header() |
SignatureError | Base exception for signature errors |
SignatureExpiredError | Raised when signature age exceeds max_age |
SignatureMismatchError | Raised when signature verification fails |
pip install -e .
python -m pytest tests/ -v
If you find this project useful: