philiprehberger-webhook-signature
HMAC-based webhook signature generation and verification with timing-safe comparison.
Installation
pip install philiprehberger-webhook-signature
Usage
Signing a Payload
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..."
Verifying a Signature
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
)
Key Rotation
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,
)
One-call sign and verify
For the common case of producing a header dict and verifying an incoming header in one step:
from philiprehberger_webhook_signature import sign_headers, verify_header
# Producer side: build HTTP-ready headers
headers = sign_headers('{"event": "order.created"}', secret="whsec_abc123")
# {"X-Webhook-Signature": "t=1700000000,sha256=..."}
# Consumer side: verify the incoming header value in one call
verify_header(
payload=request.body,
secret="whsec_abc123",
header_value=request.headers["X-Webhook-Signature"],
max_age=300.0,
)
Use header_name="X-Stripe-Signature" (or any custom name) to match your provider's convention.
Error Handling
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}")
Custom Algorithm
signed = sign(payload="data", secret="secret", algorithm="sha512")
verify(payload="data", secret="secret", signature=sig, timestamp=ts, algorithm="sha512")
Disable Expiry Check
verify(payload, secret, signature, timestamp, max_age=None)
API
| Function / Class | Description |
|---|---|
sign(payload, secret, algorithm, timestamp) |
Generate an HMAC signature for a webhook payload |
sign_headers(payload, secret, header_name, algorithm, timestamp) |
Sign a payload and return an HTTP-ready headers dict |
verify(payload, secret, signature, timestamp, algorithm, max_age) |
Verify a webhook signature with timing-safe comparison |
verify_header(payload, secret, header_value, algorithm, max_age) |
Parse a signature header and verify it in one call |
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 |
Development
pip install -e .
python -m pytest tests/ -v
Support
If you find this project useful:
License
Metadata
Release files for philiprehberger-webhook-signature 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| philiprehberger_webhook_signature-0.3.0.tar.gz | 194.5 kB | Without provenance | Details for philiprehberger_webhook_signature-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| philiprehberger_webhook_signature-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for philiprehberger_webhook_signature-0.3.0-py3-none-any.whl |
Total release size: 200.9 kB
Release files / philiprehberger_webhook_signature-0.3.0.tar.gz
| Download URL | philiprehberger_webhook_signature-0.3.0.tar.gz |
|---|---|
| Size | 194.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
afd371e604e555433973a4116e5c9efa4221ffa6bc11384f111d444a2201234d
|
|
BLAKE2b-256 checksum How to use checksums |
b6f376396f82d2887591b9670f079c7f294807b0cca9fddbb104dda85c07fc26
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Release files / philiprehberger_webhook_signature-0.3.0-py3-none-any.whl
| Download URL | philiprehberger_webhook_signature-0.3.0-py3-none-any.whl |
|---|---|
| Size | 6.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b53035ffc4b29188cd2444ddf1343950e8d83aee10a6c20f4841d5f57a6d1192
|
|
BLAKE2b-256 checksum How to use checksums |
d3e16af94c9dc2b91112a832ae1c7738139e660c5cdc594512a5f030fb543f59
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Security for philiprehberger-webhook-signature 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.