Skip to main content

HMAC-based webhook signature generation and verification with timing-safe comparison

Project description

philiprehberger-webhook-signature

Tests PyPI version Last updated

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:

Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

philiprehberger_webhook_signature-0.3.0.tar.gz (194.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

File details

Details for the file philiprehberger_webhook_signature-0.3.0.tar.gz.

File metadata

File hashes

Hashes for philiprehberger_webhook_signature-0.3.0.tar.gz
Algorithm Hash digest
SHA256 afd371e604e555433973a4116e5c9efa4221ffa6bc11384f111d444a2201234d
MD5 cbb413889930d9661ebf495f83ff2025
BLAKE2b-256 b6f376396f82d2887591b9670f079c7f294807b0cca9fddbb104dda85c07fc26

See more details on using hashes here.

File details

Details for the file philiprehberger_webhook_signature-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for philiprehberger_webhook_signature-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b53035ffc4b29188cd2444ddf1343950e8d83aee10a6c20f4841d5f57a6d1192
MD5 2fec1b8ec420bcac1e6c5cc7c6a166bf
BLAKE2b-256 d3e16af94c9dc2b91112a832ae1c7738139e660c5cdc594512a5f030fb543f59

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page