Stripe Error: No signatures found matching the expected signature for payload

2021 - Solution

I faced that error, and after a lot research I could not figure out the problem easily, but finally I could do it based in my architecture below:

//App.js

this.server.use((req, res, next) => {
  if (req.originalUrl.startsWith('/webhook')) {
    next();
  } else {
    express.json()(req, res, next);
  }
});
//routes.js

routes.post(
  '/webhook-payment-intent-update',
  bodyParser.raw({ type: 'application/json' }),

  //your stripe logic (Im using a controller, but wherever)
  (req, res) => {
    stripe.webhooks.constructEvent(...)
  }
)

Two big warnings to pay attention:

  • Make sure to send the req.headers['stripe-signature']
  • Make sure that your endpointSecret is right, if not it will still saying the same error

Tips:

  • Test it locally by installing the Stripe CLI: https://stripe.com/docs/webhooks/test

  • Verify your key on stripe dashboard or you can also make sure if you have the right key by verifying you stripe log as below:

webhook secret key example

I hope it helps you. :)


Here is code which is working for me:

app.use(bodyParser.json({
  verify: function (req, res, buf) {
    var url = req.originalUrl;
    if (url.startsWith('/stripe')) {
       req.rawBody = buf.toString();
    }
  }
}));

And then pass the req.rawBody for verification

stripe.checkWebHook(req.rawBody, signature);

Reference: https://github.com/stripe/stripe-node/issues/341


Cloud Functions automatically parses body content of known types. If you're getting JSON, then it's already parsed and available to you in req.body. You shouldn't need to add other body parsing middleware.

If you need to process the raw data, you should use req.rawBody, but I don't think you'll need to do that here.


Here is what is working for me:

add this line:

app.use('/api/subs/stripe-webhook', bodyParser.raw({type: "*/*"}))

(The first argument specifies which route we should use the raw body parser on. See the app.use() reference doc.)

just before this line:

app.use(bodyParser.json());

(it doesn't affect all your operation, just this: '/api/subs/stripe-webhook')

Note: If you are using Express 4.16+ you can replace bodyParser by express:

app.use('/api/subs/stripe-webhook', express.raw({type: "*/*"}));
app.use(express.json());

Then:

const endpointSecret = 'whsec_........'

const stripeWebhook = async (req, res) => {
    const sig = req.headers['stripe-signature'];

    let eventSecure = {}
    try {
        eventSecure = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
        //console.log('eventSecure :', eventSecure);
    }
    catch (err) {
        console.log('err.message :', err.message);
        res.status(400).send(`Webhook Secure Error: ${err.message}`)
        return
    }
    res.status(200).send({ received: true });
}