2022-12-31 10:00:00+00:00

Webhooks allow third-party services (like Stripe payments or mail servers) to notify your backend about asynchronous updates. However, because webhook endpoints are public, they are vulnerable to spam and spoofing. You must verify request signatures before executing logic.

By combining FastAPI middlewares with cryptographic signature checks, we build secure webhook receivers that process payloads safely.


1. Verifying HMAC Signatures

We calculate the SHA256 HMAC of the request body using a shared secret key, and compare it with the signature sent in the request header:

# HMAC Verification in FastAPI
import hmac
import hashlib
from fastapi import Request, HTTPException

WEBHOOK_SECRET = b"stripe_webhook_signing_secret"

async def verify_webhook_signature(request: Request):
    signature = request.headers.get("X-Signature")
    if not signature:
        raise HTTPException(status_code=400, detail="Missing signature header")
        
    body = await request.body()
    # Compute signature hash
    expected = hmac.new(WEBHOOK_SECRET, body, hashlib.sha256).hexdigest()
    
    # Secure string comparison to prevent timing attacks
    if not hmac.compare_digest(expected, signature):
        raise HTTPException(status_code=401, detail="Invalid signature")
    return body

2. Queued Ingestion

To avoid timeouts when receiving hundreds of webhooks, the endpoint validates the signature, writes the payload to a Kafka queue, and returns an HTTP 200 immediately, letting background workers process the event.