5

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});
});
Magnus
  • 265
  • 1
  • 4
  • 12
  • 1
    Possible duplicate of [Stripe Error: No signatures found matching the expected signature for payload](https://stackoverflow.com/questions/53899365/stripe-error-no-signatures-found-matching-the-expected-signature-for-payload) – James Jun 29 '19 at 08:47

5 Answers5

18

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});
});
xinthose
  • 2,529
  • 2
  • 35
  • 51
karllekko
  • 4,372
  • 1
  • 11
  • 16
  • Thank you! This was it for me. I was using the same express `app` for the webhook, but that app was using the json middleware described above. – Alex Oct 01 '21 at 15:12
10

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())
Bugzilla
  • 926
  • 1
  • 7
  • 11
  • 2
    After struggling it with for 2 days, you saved me. Thank you. – axfg Aug 01 '21 at 04:23
  • 1
    Thank you, this was exactly what I needed. (and doesn't use the deprecated bodyParser) – gbones Aug 06 '21 at 20:35
  • This fixed my issues still as of April 20, 2022. I instead used app.use(express.raw({type: "*/*})). because im using controllers, routes and express router. But it still works. THank YOU! – Alex Smith Apr 20 '22 at 18:47
1

How to get both parsed body and raw body in Express:

app.use(bodyParser.json({
  verify: (req, res, buf) => {
    req.rawBody = buf
  }
}))

Thanks to: https://flaviocopes.com/express-get-raw-body/

1

For those working with NextJS. Here is a solution I bumped on Reddit by one @ u/SiMFiCysed https://www.reddit.com/user/SiMFiCysed/

1

In addition to everything, check whsec_

enter image description here

Viktor Bogutskii
  • 735
  • 1
  • 12
  • 19
  • I didn't realize the signing secret was unique per endpoint until this prompted me to check it. Thx so much! – strattonn May 29 '22 at 11:11