PYTHON
Verifying Webhook Signatures in Python Flask
Secure your Flask application's webhook endpoints by verifying incoming signatures to ensure data integrity and authenticity from trusted sources.
import hmac
import hashlib
import json
from flask import Flask, request, abort
app = Flask(__name__)
# Your secret key for verifying webhooks.
# This should be a strong, randomly generated string,
# stored securely (e.g., in environment variables).
WEBHOOK_SECRET = 'your_super_secret_webhook_key'
@app.route('/webhook', methods=['POST'])
def handle_webhook():
# 1. Get the raw request body
request_body = request.get_data()
# 2. Get the signature from the header. The exact header name
# will depend on the service sending the webhook (e.g., 'X-Hub-Signature', 'X-Stripe-Signature').
# For demonstration, let's assume 'X-My-Signature'.
signature_header = request.headers.get('X-My-Signature')
if not signature_header:
abort(400, description='Signature header missing')
# 3. Calculate the expected signature
# The signature algorithm (e.g., 'sha256') and encoding (e.g., 'hex')
# also depend on the webhook provider.
expected_signature = hmac.new(
WEBHOOK_SECRET.encode('utf-8'),
msg=request_body,
digestmod=hashlib.sha256
).hexdigest()
# 4. Compare the expected signature with the received one
# Use hmac.compare_digest for constant-time comparison to prevent timing attacks.
if not hmac.compare_digest(expected_signature, signature_header):
abort(403, description='Invalid webhook signature')
# 5. If signature is valid, process the webhook payload
try:
payload = json.loads(request_body)
print(f"Received valid webhook: {json.dumps(payload, indent=2)}")
# Perform your webhook processing here (e.g., update database, trigger events)
return {'status': 'success'}, 200
except json.JSONDecodeError:
abort(400, description='Invalid JSON payload')
if __name__ == '__main__':
# To run:
# 1. pip install Flask
# 2. python your_script_name.py
# 3. Send a POST request with the 'X-My-Signature' header
# You'll need to generate a signature for testing:
# Example:
# import hmac, hashlib, json
# secret = 'your_super_secret_webhook_key'.encode('utf-8')
# payload = {'event': 'test.event', 'data': {'id': 123}}
# body = json.dumps(payload, separators=(',', ':')).encode('utf-8') # Ensure no whitespace
# signature = hmac.new(secret, msg=body, digestmod=hashlib.sha256).hexdigest()
# print(f"Signature: {signature}")
# curl -X POST -H "Content-Type: application/json" -H "X-My-Signature: <paste_signature_here>" -d '{"event":"test.event","data":{"id":123}}' http://127.0.0.1:5000/webhook
app.run(debug=True)
How it works: This Flask snippet demonstrates how to verify webhook signatures, a crucial security measure. When a third-party service sends a webhook, it often includes a signature in the request headers, generated using a shared secret and the request body. This code retrieves the raw request body and the signature, calculates its own expected signature using the same algorithm, and then securely compares it to the received signature using `hmac.compare_digest`. If the signatures don't match, the request is rejected, preventing processing of potentially fraudulent or tampered webhook events.