Gijs van Beusekom
Gijs van Beusekom

Reputation: 375

Stripe webhook with Google Cloud Functions keeps giving Webhook Error: No signatures found matching the expected signature for payload

I know this question has been asked before, but if I implement the solutions in other questions I still get an error.

The situation is:

I try to test my Stripe webhook to a Node.js/Express/Google Cloud Functions backend. If I only implement the code form the documentation I get the error: No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe?

When I search for this error here on StackOverflow (Stripe Error: No signatures found matching the expected signature for payload) I read that:

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 the code including the code from the Stripe documentation:

const functions = require('firebase-functions');
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const admin = require('firebase-admin');
const stripe = require('stripe')('sk_test_****');
const cron = require('node-cron');

// Stripe
const endpointSecret = "whsec_****"

const fulfillOrder = (session) => {
    // TODO: fill me in
    console.log("Fulfilling order", session);
  }
  
 app.post('/webhook', bodyParser.raw({type: 'application/json'}), (request, response) => {
    const payload = request.body;
    const sig = request.headers['stripe-signature'];
  
    let event;
  
    try {
      event = stripe.webhooks.constructEvent(payload, sig, endpointSecret);
    } 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...
      fulfillOrder(session);
    }
  
    response.status(200);
  });

This gives the well know error: Webhook Error: No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe? https://github.com/stripe/stripe-node#webhook-signing

So the way I understand it is when using Google Cloud Functions I need to use:

const payload = request.rawBody;

This gives the same error. It's either this error or a timeout error.

I've tried this:

app.post('/webhook', bodyParser.raw({type: "*/*"}), (request, response) => {
    const payload = request.rawBody

This gives a timeout error.

What am I missing?

Upvotes: 4

Views: 968

Answers (1)

Justin Michael
Justin Michael

Reputation: 6475

Node frameworks and middleware will often modify the body (even the raw body) in ways that makes the Stripe signature verification fail. Unfortunately there isn't a single, bulletproof fix, but there are several approaches and workarounds in this GitHub issue that I recommend you take a look at: https://github.com/stripe/stripe-node/issues/341

Hopefully one of those fixes will work for you. In general the main thing is to get the raw body out of the request as soon as possible, before anything else has a chance to modify it.

Upvotes: 2

Related Questions