stripe-webhook-signature-verification
Stripe Webhook Signature Verification
Concept of the skill
What it is: The security check that proves an incoming Stripe webhook was signed by Stripe before any payment logic runs. Mental model: The raw request body, signature header, and webhook secret form one verification tuple; change any part and the event is untrusted. Why it exists: Webhook routes are public endpoints that can trigger billing and fulfillment, so authenticity has to be established before routing. What it is NOT: It is not payment-event routing, general HTTP signature validation, or Stripe API usage outside webhook delivery. Adjacent concepts: HMAC verification, raw request bodies, replay tolerance, idempotency keys. One-line analogy: It is the seal check before opening the payment envelope. Common misconception: Parsing JSON first is harmless; transforming the raw bytes invalidates the signature comparison.
Coverage
- The raw-body requirement — why
stripe.webhooks.constructEvent()requires the unparsedBufferfrom the request body, and how Next.js App Router routes expose it viarequest.arrayBuffer() - HMAC-SHA256 verification — how
constructEvent(rawBody, signature, secret)reconstructs and compares the Stripe signature internally - Replay protection — the 300-second tolerance window Stripe checks against the
t=timestamp embedded in thestripe-signatureheader; when to tighten it - Environment-specific secrets —
STRIPE_WEBHOOK_SECRETfor production vswhsec_...from the Stripe CLI--forward-tosession in development; why they must never be swapped - Idempotency key pattern — recording the
event.idin Postgres before processing so a retried delivery does not double-charge or double-fulfill