rightengineer
rightengineer

Reputation: 71

Stripe Webhook 400 error. Raw request body issues

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

Answers (2)

Joseph Astrahan
Joseph Astrahan

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

orakaro
orakaro

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

Related Questions