Possible error in README example, "Testing Webhook Signing"
Describe the bug
After implementing a webhook endpoint in a typescript express project, I first tested locally using the Stripe CLI. Everything worked as expected.
I then created automated tests for CI by following these instructions outlined in the README.
When running the tests, I consistently received the following error:
Webhook signature verification failed. StripeSignatureVerificationError: No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe?
After some debugging, I found the following change to resolve the issues:
Original: const payloadString = JSON.stringify(payload, null, 2);
Updated: const payloadString = JSON.stringify(payload);
To Reproduce
- Create a webhook endpoint that verifies the
stripe-signatureheader - Test using the Stripe CLI
- When CLI tests pass, create an automated test following the instructions here
- Run the test
Expected behavior
The test should pass.
Code snippets
// Below Code Works
const signature = stripe.webhooks.generateTestHeaderString({
payload: JSON.stringify(payload),
secret: stripeSigningSecret,
})
// Code from README, does not work
const signature = stripe.webhooks.generateTestHeaderString({
payload: JSON.stringify(payload, null, 2),
secret: stripeSigningSecret,
})
OS
Docker node:lts
Node version
Node v16.16.0
Library version
stripe node 10.0.0
API version
2022-08-01
Additional context
This could possibly be due to some sort of environment being out of sync with my local setup. That said, if it is indeed an issue with the supplied example, it would be good to fix the README.
If confirmed to be an issue with the example, I would be happy to open a PR.
Hey @summer-jordan! Thank you for the report. Unfortunately, I can't reproduce the error. Are you able to provide the call stack for the error or share a little more from your test setup?
@summer-jordan We are closing this issue as we have not heard back from you in a month. If you still are seeing problems with the example in the readme, please log a new issue with the details asked by @kamil-stripe above.
I am seeing the same thing using supertest.
const payloadString = JSON.stringify(payload, null, 2) // fails const payloadString = JSON.stringify(payload); // works
I suspect this depends on how the testing library serializes the payload. It has to match. Would probably good to point that out in the README.
Apologies for the delay in this response! For future reference, the raw payload passed in to generateTestHeaderString must be the same as the raw payload that's passed in to constructEvent (which is the case in the README example). I agree with @tcurdt that if you are passing the payload as an object to an HTTP client or other testing library, it will serialize your object under the hood and may not call JSON.stringify with the same parameters.
In this case, it is up to the user to decide how to ensure that the serialized payloads passed in to generateTestHeaderString and constructEvent are equivalent. You can specify the raw body in your test request to guarantee the serialized payload matches, or update the payloadString passed in to generate test header to match what your testing library is doing under the hood (e.g., for supertest, it seems to be JSON.stringify(payload)).