Reputation: 71
I've been following Stripes documentation on setting up webhooks and testing locally through their Stripe CLI. I can successfully create events, but I receive a response of 400 POST.
2021-12-14 23:18:53 --> payment_intent.created [evt_3K6ox6LqfpEEJtVG0yhTBKDf]
2021-12-14 23:18:53 <-- [400] POST http://localhost:4242/webhook [evt_3K6ox6LqfpEEJtVG0yhTBKDf]
No matter what I do, I always receive a "No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe?" error. Looking through previous questions relating to this, the issue revolves around passing raw data.
I have doublechecked that my webhook secret matches that of the what the CLI gives me.
Here is the latest attempt:
// 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'];
const rawBody = req.body
let event;
try {
event = stripe.webhooks.constructEvent( rawBody, 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});
});
Upvotes: 5
Views: 5574
Reputation: 9082
For 2022, change the app.use(express.json())
to this.
app.use(express.json({
limit: '5mb',
verify: (req, res, buf) => {
req.rawBody = buf.toString();
}
}));
Then you have to change the webhook code to use the rawBody variable that was added correctly and remove the middleware express.raw({type:'application/json'})
since that won't be needed once you have the rawBody variable added to the request anyways.
app.post('/webhook', (request, response) => {
const sig = request.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(request.rawBody, sig, endpointSecret); //@JA - Had to modify this to take the rawBody since this is what was needed.
} catch (err) {
response.status(400).send(`Webhook Error: ${err.message}`);
return;
}
// Handle the event
switch (event.type) {
case 'payment_intent.succeeded':
const paymentIntent = event.data.object;
// Then define and call a function to handle the event payment_intent.succeeded
break;
// ... handle other event types
default:
console.log(`Unhandled event type ${event.type}`);
}
// Return a 200 response to acknowledge receipt of the event
response.send();
});
The nice part about this fix is you can continue to use express.json() middleware to continue to parse the json from your API's as normal and none of your code should break :).
Upvotes: 9
Reputation: 1981
It's a common issue and could depend on your setup and framework. If you are using Node, I recommend going through this Github issue and see if workarounds there work for you.
Lastly you can write into Stripe Support and their dev could help figure out what went wrong.
Upvotes: 0