Back to all terms
Payment
Paymentsbasic

Webhook Verification (Stripe)

Cryptographically verifying that incoming webhook payloads genuinely originate from Stripe by validating the signature in the Stripe-Signature header against your webhook signing secret.

Also known as: webhook signature verification, Stripe webhook signing, webhook security, event signature validation

Description

Stripe webhook verification ensures that the events your server receives are authentic and haven't been tampered with. Every webhook Stripe sends includes a Stripe-Signature header containing a timestamp and one or more HMAC-SHA256 signatures. Your server verifies the signature by computing the expected signature from the raw request body and your webhook endpoint's signing secret (whsec_...), then comparing it against the signatures in the header. Stripe's SDK provides stripe.webhooks.constructEvent() which performs this verification and returns the parsed event object, or throws an error if verification fails.

The verification process is sensitive to how your web framework handles request bodies. The signature is computed over the raw request body bytes, so if your framework parses the body as JSON before it reaches your webhook handler, the re-serialized body may differ from the original. Express requires using express.raw({type: 'application/json'}) on the webhook route instead of express.json(). Next.js App Router provides the raw body via request.text(). Failing to preserve the raw body is the most common cause of webhook verification failures.

Stripe also includes a timestamp in the signature to protect against replay attacks. The constructEvent() function accepts a tolerance parameter (default 300 seconds) that rejects events with timestamps too far in the past. In production, your webhook endpoint should always verify signatures and reject unverified payloads with a 400 status. During development, you can use the Stripe CLI (stripe listen --forward-to) to forward test events with proper signatures to your local server.

Prompt Snippet

Configure the webhook endpoint route to receive the raw request body (Express: express.raw({type: 'application/json'}), Next.js: export const config = { api: { bodyParser: false } }) and verify with stripe.webhooks.constructEvent(rawBody, sig, endpointSecret) inside a try/catch, returning 400 on StripeSignatureVerificationError. Store the webhook signing secret (whsec_...) in environment variables, separate from your Stripe secret key. Set the signature tolerance to 300 seconds (default) to reject replay attacks. Always return a 200 response promptly after receiving the event, processing it asynchronously via a job queue to avoid Stripe's 20-second timeout.

Tags

webhookssecuritystripesignatureverificationhmac