Stripe webhook signature checker
"No signatures found matching the expected signature for payload": paste the header, the body and the secret, and see which of the three is not what you think it is.
Loading…
How Stripe signs an event
Stripe takes the timestamp, a dot, and the body of the request exactly as it was sent, computes an HMAC-SHA256 of that string with the signing secret of the endpoint, and puts the result in the Stripe-Signature header as t=timestamp,v1=signature. To verify, you redo the same computation and compare. This page does it in your browser with the Web Crypto API.
Why verification fails, in order of likelihood
- The body was parsed before it was verified. A framework that turns the JSON into an object and back does not give you the same bytes: spacing, key order and escapes change. Verify on the raw body. The checker tells you when the signature matches the body as received by Stripe but not the re-serialised one, or the other way round.
- The wrong secret. Each endpoint has its own
whsec_secret, test mode and live mode have different ones, and the Stripe CLI prints yet another forstripe listen. An API key (sk_) is not a signing secret. - A proxy changed the body: a gateway that re-encodes, trims a trailing newline, or decodes the text with another charset.
- The clock. Libraries refuse a timestamp more than five minutes old to block replays. Replaying a saved event by hand fails for that reason alone.
Not having to do this yourself
If all you want from the webhook is a message in a channel when money moves, Paybell does the verification for you and posts to Slack, Discord or Teams.
Questions
- Is it safe to paste my signing secret here?
- The computation runs in your browser with the Web Crypto API and nothing you paste is sent to a server: you can check in the network tab of your developer tools, or disconnect before pasting. A signing secret can only verify or forge events for one endpoint; if in doubt, roll it in Stripe afterwards.
- Can it generate a signature for my own test?
- Yes. "Sign this body now" writes a Stripe-Signature header for the body and secret you entered, with the current time, so you can call your own endpoint with curl.
- What does the error "No signatures found matching the expected signature for payload" mean?
- The library computed a signature from the body and secret it was given and it differs from the one in the header. Nine times out of ten the body is not the raw one, or the secret belongs to another endpoint or mode.