'Stripe webhook error: No signatures found matching the expected signature for payload
I am using the code provide by Stripe to test a webhook. The Stripe secret and the endpoint secret have been triple checked.
Stripe version: 6.19 Body-Parser: 1.19
When I test webhook on the Stripe dashboard I get the result: (Test webhook error: 400) No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe?
Any help would be appreciated.
var bodyParser - require('body-parser);
// Using Express
const app = require('express')();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
const stripe = require('stripe')('sk_test_VPw...');
// Find your endpoint's secret in your Dashboard's webhook settings
const endpointSecret = 'whsec_...';
// Use body-parser to retrieve the raw body as a buffer
const bodyParser = require('body-parser');
// Match the raw body to content type application/json
app.post('/webhook', bodyParser.raw({type: 'application/json'}), (request, response) => {
const sig = request.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret); //NOT WORKING!
} catch (err) {
return response.status(400).send(`Webhook Error: ${err.message}`);
}
// Handle the checkout.session.completed event
if (event.type === 'checkout.session.completed') {
const session = event.data.object;
// Fulfill the purchase...
handleCheckoutSession(session);
}
// Return a response to acknowledge receipt of the event
response.json({received: true});
});
Solution 1:[1]
Usually this is due to something on your side parsing or modifying the raw request string before the signature is checked(so the signature is computed against a modified string, not the exact one Stripe sent). In this case it looks like the JSON express middleware is doing that:
app.use(express.json());
.
Stripe has an example of using a raw bodyParser middleware on the webhook endpoint instead so that your code gets the raw string that's required :
// Use JSON parser for all non-webhook routes
app.use((req, res, next) => {
if (req.originalUrl === '/webhook') {
next();
} else {
express.json()(req, res, next);
}
});
// Stripe requires the raw body to construct the event
app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
const sig = req.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(req.body, sig, webhookSecret);
} catch (err) {
// On error, log and return the error message
console.log(`? Error message: ${err.message}`);
return res.status(400).send(`Webhook Error: ${err.message}`);
}
// Successfully constructed event
console.log('? Success:', event.id);
// Return a response to acknowledge receipt of the event
res.json({received: true});
});
Solution 2:[2]
One liner plus no deprecated bodyParser. Make sure to define your endpoint's parser before the generic one, aka express.json().
app.use('/stripe/webhook', express.raw({type: "*/*"}))
app.use(express.json())
Solution 3:[3]
How to get both parsed body and raw body in Express:
app.use(bodyParser.json({
verify: (req, res, buf) => {
req.rawBody = buf
}
}))
Solution 4:[4]
For those working with NextJS. Here is a solution I bumped on Reddit by one @ u/SiMFiCysed https://www.reddit.com/user/SiMFiCysed/
Solution 5:[5]
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | xinthose |
Solution 2 | |
Solution 3 | Michal Jána |
Solution 4 | Samson Ssali |
Solution 5 | Viktor Bogutskii |