Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Webhook signature verification and bodyParser.json issue #341

Closed
manu-st opened this issue May 26, 2017 · 83 comments
Closed

Webhook signature verification and bodyParser.json issue #341

manu-st opened this issue May 26, 2017 · 83 comments

Comments

@manu-st
Copy link

manu-st commented May 26, 2017

If you use in your express app bodyParser.json() for all routes, and then have a dedicated route for stripe's webhook, then the second call to bodyParser.json({verify: ...}) as done in the example has no effect.

I have the following code:

app.use(bodyParser.json());
...
app.use('/stripeUrl', stripeRoute);
app.use('/user', userRoute);
....

The StripeRoute is defined exactly as the example.

Unfortunately it doesn't work. Only if I comment out the first call to bodyParser.json does it work. Which mean that I cannot have a call to bodyParser just for my route, I need to add the verify function my top call to bodyParser.json and to avoid having to pay for the conversion all the time check for the Url to match my stripe route.

Maybe the doc should reflect that, and if it is supposed to work then some guidance as it doesn't for me.

Thanks!

@brandur-stripe
Copy link
Contributor

@jlomas-stripe Would you mind providing some guidance/advice on this one? Thanks!

@ronzeidman
Copy link

ronzeidman commented May 28, 2017

This is the way I'm handling it:

// main file
app
    .set(...)
    .use(...<helmet, cors, compression, logging...>)
    .use('/stripe-webhooks', stripeWebhookRoutes) //the webhooks must come before the default json body parser
    .use(bodyParser.json())

// webhook handling file

export const stripeWebhookRoutes = Router()
    .use(bodyParser.raw({type: '*/*'}))
    .post('', eventParser(process.env.STRIPE_WEBHOOK_SECRET), mainStripeWebhook)
    .post('/connect', eventParser(process.env.STRIPE_WEBHOOK_CONNECT_SECRET), connectStripeWebhook);

function eventParser(secret) {
    return (req, res, next) => {
        try {
            req.body = stripe.webhooks.constructEvent(
                req.body.toString(),
                req.headers['stripe-signature'],
                secret);
        } catch (error) {
            return res.sendStatus(httpStatus.BAD_REQUEST);
        }
        return next();
    }
}

@manu-st
Copy link
Author

manu-st commented May 29, 2017

@ronzeidman Thanks for sharing your solution, mine is:

app.use(bodyParser.json({
    // Because Stripe needs the raw body, we compute it but only when hitting the Stripe callback URL.
    verify: function(req,res,buf) {
        var url = req.originalUrl;
        if (url.startsWith('/stripe-webhooks')) {
            req.rawBody = buf.toString()
        }
    }}));

At the end it does what we need but I think it should be provided in the doc as currently you might think that the example would be easily plug-able as is but it is not.

@jlomas-stripe
Copy link
Contributor

This is a really good point, but I think it's going to be pretty specific to how your application is implemented.

I guess there are a number of different ways this could be implemented; the idea of the documentation example was just to provide a way to get it working quickly.

@manu-st
Copy link
Author

manu-st commented Jun 1, 2017

It might be good to highlight this in the example that proper care has to be done for the bodyParser. Especially in the official docs at https://stripe.com/docs/webhooks where there is no mention on how to set this up, and I think the following comment:

// We use a router here so it can use its own `bodyParser` instance to add
// the raw POST data to the `request`

is actually confusing making you believe that it will work all the time because it is in its own route.

@lincolnthree
Copy link

Yep. I ran into this too. Still not sure how I want to handle it.

@floatingLomas
Copy link

floatingLomas commented Jun 9, 2017

Those docs were based on my example so ... this is my bad.

I'll take a look and see if there's another/better/easier/more-consistent way to get at the raw body in Express without using body-parser.

@jlomas-stripe
Copy link
Contributor

jlomas-stripe commented Jun 9, 2017

Ok, so you can accomplish the same with just simple middleware:

function addRawBody(req, res, next) {
  req.setEncoding('utf8');

  var data = '';

  req.on('data', function(chunk) {
    data += chunk;
  });

  req.on('end', function() {
    req.rawBody = data;

    next();
  });
}

@joaoreynolds
Copy link

I'm pulling my hair out and could really use some insight. I've tried all methods mentioned above (using bodyParser.raw, using the addRawBody middleware).

Note: this is an event for a connected account, I need to handle the account.application.deauthorized event. Not sure if the fact that it's a connected account has anything to do with it.

I'm using the latest stripe package v4.24.0

Here's my first middleware/route handler (no other middleware above this):

app.post('/stripe-webhooks', bodyParser.raw({type: '*/*'}), postStripeWebhooks)
//...further down I do the standard, json parser (but even if I remove that it makes not difference)
app.use(bodyParser.json())

And postStripeWebhooks:

const body = req.body.toString()
try {
  const event = stripe.webhooks.constructEvent(body, req.headers['stripe-signature'], config.stripeWebhookSecret)
  console.log(event)
}
catch(e) {
  console.log('Error', e.message)
}

Every way I go about it I get the same result: No signatures found matching the expected signature for payload I've also tried everything from the example at https://github.com/stripe/stripe-node/blob/master/examples/webhook-signing/express.js Please help!

@jlomas-stripe
Copy link
Contributor

@joaoreynolds If you use the 'simple middleware' from the example, and use request.rawBody (instead of req.body.toString()), does that work?

@joaoreynolds
Copy link

*epic facepalm

I just thought, "know what? I better check my webhook secret key even though I'm sure I have that set".

I had the wrong effing webhook secret key stored in my production environment variables!

(That moment when you realize you're a terrible developer and nobody should hire you, haha)

Thanks @jlomas-stripe for being willing to help.

In an effort to be somewhat productive to this thread, after cleaning my code, I found that @manu-st 's version was the least-invasive to my app, allowing me to use bodyParser.json() on the rest of my app.

@jlomas-stripe
Copy link
Contributor

You're very welcome - any time! :)

@Ontokrat
Copy link

Ontokrat commented Oct 20, 2017

My implementation in Meteor - thanks to @manu-st.
I use Picker as router Server Side (allow filter and sub-routes).
Body-parser in JSON for every webhook / exception for Stripe: verification of webhook's signature (raw) and then handling the same webhook in JSON.

import bodyParser from 'body-parser';
import { Picker } from 'meteor/meteorhacks:picker';

// Middleware declaration
Picker.middleware(bodyParser.json({
  limit: '10MB',
  verify: function(req,res,buf) {
    var url = req.originalUrl;
    if (url.startsWith('/stripe-webhooks')) {
      req.rawBody = buf.toString()
    }
  }
}));

// filtered main route
var postRoutes = Picker.filter(function(req, res, buf) {
  var url = req.originalUrl;
  if (url.startsWith('/stripe-webhooks')) {
    // verify webhook's signature if he comes from stripe
    // 'req.rawBody' available here
    // Got only 'empty constructEvent' from official library ( let event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret); )
    // adapt here https://github.com/stripe/stripe-node/blob/master/lib/Webhooks.js
    // see details: https://stripe.com/docs/webhooks#verify-manually
  }
    // handle only POST requests
    return req.method == "POST"
});


// from route, handling webhook and sending request
postRoutes.route('url', (request, response) => {
  // handle result here
});

@lomegg
Copy link

lomegg commented Mar 25, 2018

The issue is still present and driving me mad.

@floatingLomas
Copy link

@lomegg Can you provide more details on your issue and the specifics of your implementation, ie versions, where/how you're running it?

@lomegg
Copy link

lomegg commented Mar 26, 2018

@floatingLomas I am running it with express when getting a webhook after the simple cart charge (those are not required but I use them as confirmation in my eCommerce, so I need them to be signature verified). My issue is that I am getting object instead of json even after I use bodyParser as middleware like this
var rawParser = bodyParser.raw({type: "*/*"});
app.all('/webhook', rawParser, keystone.middleware.api, routes.api.webhook.process);

Note that verify option in bodyParser doesn't get called if I assign function to it.
No matter how I try, I can't get webhook request body in any form other than javascript object.
And if I convert that object to json, I'm getting validation error because it's not pure request body.

@jlomas-stripe
Copy link
Contributor

@lomegg What does keystone.middleware.api do? Does that overwrite the body by chance?

@lomegg
Copy link

lomegg commented Mar 26, 2018

@jlomas-stripe It provides some api methods, I was testing with it switched off to the same effect. But I will double check on that again, thanks

@lomegg
Copy link

lomegg commented Mar 31, 2018

Still getting that SyntaxError: Unexpected token o in JSON at position 1 even after I chained bodyParser

@floatingLomas
Copy link

Best bet is to share the code in routes.api.webhook.process here, or probably better, with Support: https://support.stripe.com/email

@nabilfreeman
Copy link

nabilfreeman commented Apr 19, 2018

Thanks @manu-st for such an elegant solution - using req.bodyRaw instead of req.body worked perfectly.

It meant that we didn't have to refactor our Express routing. Great job!

@dburles
Copy link

dburles commented Jun 26, 2018

@lomegg I had the same issue and I found that another part of the application was adding in a bodyParser.json() middleware.

@pincheira
Copy link

@manu-st 's solution is what I got it working with. The thing is that most people's express setup is doing:

app.use(bodyParser.json());

which sets the json parser for all body objects by default. So I just now pass a setup object to it that includes the block that @manu-st showed.

app.use(bodyParser.json(setupForStripeWebhooks));

That object being:

const setupForStripeWebhooks = {
  // Because Stripe needs the raw body, we compute it but only when hitting the Stripe callback URL.
  verify: function (req, res, buf) {
    var url = req.originalUrl;
    if (url.startsWith('/webhooks/stripe')) {
      req.rawBody = buf.toString();
    }
  }
};

@karlr-stripe
Copy link

(posting this for visibility for people who find this through search engines) If you use express-generator to create your project, it will likely add the app.use(express.json()); line to your app.js which also sets the JSON parser on all request bodies by default. So that is another thing to watch out for!

@wdmtech
Copy link

wdmtech commented Sep 18, 2018

For those seeking solutions for Feathers.js (like I was) check out feathers-stripe-webhooks which will do all this for you 👍

@DanielGibbsNZ
Copy link

For those seeking solutions for Feathers.js (like I was) check out feathers-stripe-webhooks which will do all this for you 👍

Unfortunately this does not seem to be the case. I get the same problem even when using feathers-stripe-webhooks.

@stevus
Copy link

stevus commented Nov 16, 2018

Why do these issues keep getting closed? Feels like there's a big issue with the signature validation code around needing the raw body. I am also having this problem but hard to find a solution when every issue gets diagnosed as user error.

@taimoorgit
Copy link

My adaptation of @kurry421's answer:

The webhook:

const router = require('express').Router()
const stripe = require('stripe')(process.env.STRIPE_SECRET)
const bodyParser = require('body-parser')

// https://stripe.com/docs/payments/checkout/fulfill-orders#fulfill
// Do not change responses, since there are standard from stripe
// NEED to use body parser, express.json for some reason is not compatible

router.post('/checkout_session_completed', async (req, res) => {
    const sig = req.headers['stripe-signature']
    const payload = req.body

    let event
    try {
        event = stripe.webhooks.constructEvent(payload, sig, process.env.STRIPE_ENDPOINT_SECRET)
    } catch (err) {
        return res.status(400).json(`Webhook Error: ${err.message}`)
    }

    // Handle the checkout.session.completed event
    if (event.type === 'checkout.session.completed') {
        const session = event.data.object

        // Fulfill the purchase...
        console.log(session)
    }

    res.sendStatus(200)
})

module.exports = router

My app.js:

const express = require('express')
const mongoose = require('mongoose')
const dotenv = require('dotenv')
const cors = require('cors')
const bodyParser = require('body-parser')

// Setup server
dotenv.config()
mongoose.set('useNewUrlParser', true)
mongoose.set('useFindAndModify', false)
mongoose.set('useCreateIndex', true)
mongoose.set('useUnifiedTopology', true)
mongoose.connect(process.env.MONGODB, { useNewUrlParser: true, useUnifiedTopology: true }, (err) => {
    if (err) {
        console.log(`MongoDB error: ${err}`)
    } else {
        console.log('Connected to MongoDB!')
    }
})
const app = express()
app.use(cors())
app.use('/webhooks/stripe', bodyParser.raw({ type: '*/*' }), require("./webhooks/stripe"))
app.use(express.json())

// API routes
app.use('/api/v1/auth', require('./auth/auth'))
app.use('/api/v1/images', require('./image/upload'))
app.use('/api/v1/images', require('./image/search'))
app.use('/api/v1/images', require('./image/search_related'))
app.use('/api/v1/images', require('./image/delete'))
app.use('/api/v1/images', require('./image/update'))
app.use('/api/v1/images', require('./image/view'))
app.use('/api/v1/marketplace', require('./marketplace/purchase'))
app.use('/api/v1/marketplace', require('./marketplace/coupons'))
app.use('/api/v1/marketplace', require('./marketplace/purchases'))

// Start server
let port = process.env.PORT
if (!port) {
    port = 5000
}
app.listen(port, () => {
    console.log(`Server started on ${port}!`)
})

A few things to keep in mind:

  • Make sure to setup cors() first
  • Setup express.json() (if you're using it) AFTER setting up the webhook route
  • Actually SEND a status rather than just setting res.status(200)

@Aadmaa
Copy link

Aadmaa commented Feb 23, 2021

The raw-body package is an easy solution if you don't need body-parser. Then in your server setup you can just send the (req, res) tuple to your endpoint handler, as-is.

app.post('/stripehooks', (req, res) => stripehooks(req, res))

In stripehooks:
import getRawBody from 'raw-body';

[...]

const rawBody = await getRawBody(req);

try {
  event = stripe.webhooks.constructEvent(rawBody, sig, whSecret);
} catch (err) {
  return res.status(401).end(`Error validating webhook (test mode): ${err.message}`);
}

@shumiyao
Copy link

shumiyao commented Apr 13, 2021

Works if you are:

  • Using Express version: ^4.17.1
  • Struggling with bodyParser deprecated problem.

My solution

Try the following lines before you start up your express server:

const express = require('express');
const app = express();

...

app.use("/your/stripe/webhook/endpoint", express.raw({ type: "*/*" }));
app.use(express.json());

...

Note:

  • You will need to change "/your/stripe/webhook/endpoint" to your own.

@gieoon
Copy link

gieoon commented Jul 30, 2021

The above example has been added as an example
https://github.com/stripe/stripe-node/blob/master/examples/webhook-signing/node-express/express.js

@aneeshjoshi
Copy link

For what it's worth, I've encountered this on Firebase Cloud Functions and the StackOverflow issue that lead me here was from a Firebase user as well.

@cjavilla-stripe is right that Firebase is doing its own parsing of body content in Express. Here it is in their documentation:

In Node.js, the body of the request is automatically parsed based on the content-type header and made available via your HTTP function's arguments.

If you're using Firebase Cloud Functions, you should already have access to the req.rawBody prop without the fixes above. Here's an issue where it's mentioned:

While rawBody was removed from express a while ago, Cloud Functions still provides it.

If you're using TypeScript with GCF's default settings you won't be able to deploy because of a TS error like this:

Property 'rawBody' does not exist on type 'Request<ParamsDictionary, any, any>'.

Firebase provides its own types though and in this case I think you can safely assert the type like this:

import express from 'express'
import { https } from 'firebase-functions'

const app = express()

app.post('/', async (req, res) => {
  // ...
  const firebaseRequest = req as https.Request
  event = stripe.webhooks.constructEvent(
    firebaseRequest.rawBody,
    sig,
    ENDPOINT_SECRET,
  )
  // ...
}

This solved the issue for me.

This was a lifesaver on firebase cloud functions. Thanks @mitchellbutler.

@stathisaska
Copy link

stathisaska commented Jun 22, 2022

@jlomas-stripe

{
  req.setEncoding('utf8');

  var data = '';

  req.on('data', function(chunk) {
    data += chunk;
  });

  req.on('end', function() {
    req.rawBody = data;

    next();
  });
}

Can I use that in Node Red ? And if so, where do I put it ? I tried in settings.js as follows, but when I deploy the flow I get an internal server error

     httpAdminMiddleware: function addRawBody (req,res,next) {
  req.setEncoding('utf8');

  var data = '';

  req.on('data', function(chunk) {
    data += chunk;
  });

  req.on('end', function() {
    req.rawBody = data;

    next();
  });
},

@pencilcheck
Copy link

Still doesn't work for me, still getting the same error.

@NithinSGowda
Copy link

Doesn't work in GCP App engine, it parses it into JSON same as firebase does, but rawBody isn't available as that of a firebase request.
Why can't the SDK accept a parsed JSON in constructEvent? Any specific security reason?

@iBobik
Copy link

iBobik commented Nov 9, 2022

Why can't the SDK accept a parsed JSON in constructEvent? Any specific security reason?

Verification of signature requires to have the data exactly the same like it was on the signer's machine. This could be guaranteed on string or buffer, but unserialised object does not guarantee e.g. properties order.

@Snouzy
Copy link

Snouzy commented Feb 5, 2023

Hey ! If you are on Typescript, here's a middleware that you can add to your route :

interface RequestWithRawBody extends Request {
  rawBody: Buffer;
}

const addRawBody = () => (req: Stream, _: Response, next: NextFunction) => {
  const chunks: Buffer[] = [];

  req.on("data", (chunk: Buffer) => {
    chunks.push(chunk);
  });

  req.on("end", () => {
    ((req as unknown) as RequestWithRawBody).rawBody = Buffer.concat(chunks);
    next();
  });
};

@douglas-artoh
Copy link

hey friends if you are using the bodyParser in the app, the validation will not work.

app.use(bodyParser.json());

replace with the code below

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

in the function to build the event pass the rawBody

event = stripe.webhooks.constructEvent(req.rawBody, sig, endpointSecret);

after this change here it worked

@russtack
Copy link

russtack commented Mar 6, 2023

hey friends if you are using the bodyParser in the app, the validation will not work.

app.use(bodyParser.json());

replace with the code below

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

in the function to build the event pass the rawBody

event = stripe.webhooks.constructEvent(req.rawBody, sig, endpointSecret);

after this change here it worked

Many Many thanks Douglas, out of all solutions this one worked for me!

@yura0seredyuk
Copy link

using rawBody instead of body helps me
event = stripe.webhooks.constructEvent(req.rawBody, sig, endpointSecret);

@bajere
Copy link

bajere commented Aug 22, 2023

My adaptation of @kurry421's answer:

The webhook:

const router = require('express').Router()
const stripe = require('stripe')(process.env.STRIPE_SECRET)
const bodyParser = require('body-parser')

// https://stripe.com/docs/payments/checkout/fulfill-orders#fulfill
// Do not change responses, since there are standard from stripe
// NEED to use body parser, express.json for some reason is not compatible

router.post('/checkout_session_completed', async (req, res) => {
    const sig = req.headers['stripe-signature']
    const payload = req.body

    let event
    try {
        event = stripe.webhooks.constructEvent(payload, sig, process.env.STRIPE_ENDPOINT_SECRET)
    } catch (err) {
        return res.status(400).json(`Webhook Error: ${err.message}`)
    }

    // Handle the checkout.session.completed event
    if (event.type === 'checkout.session.completed') {
        const session = event.data.object

        // Fulfill the purchase...
        console.log(session)
    }

    res.sendStatus(200)
})

module.exports = router

My app.js:

const express = require('express')
const mongoose = require('mongoose')
const dotenv = require('dotenv')
const cors = require('cors')
const bodyParser = require('body-parser')

// Setup server
dotenv.config()
mongoose.set('useNewUrlParser', true)
mongoose.set('useFindAndModify', false)
mongoose.set('useCreateIndex', true)
mongoose.set('useUnifiedTopology', true)
mongoose.connect(process.env.MONGODB, { useNewUrlParser: true, useUnifiedTopology: true }, (err) => {
    if (err) {
        console.log(`MongoDB error: ${err}`)
    } else {
        console.log('Connected to MongoDB!')
    }
})
const app = express()
app.use(cors())
app.use('/webhooks/stripe', bodyParser.raw({ type: '*/*' }), require("./webhooks/stripe"))
app.use(express.json())

// API routes
app.use('/api/v1/auth', require('./auth/auth'))
app.use('/api/v1/images', require('./image/upload'))
app.use('/api/v1/images', require('./image/search'))
app.use('/api/v1/images', require('./image/search_related'))
app.use('/api/v1/images', require('./image/delete'))
app.use('/api/v1/images', require('./image/update'))
app.use('/api/v1/images', require('./image/view'))
app.use('/api/v1/marketplace', require('./marketplace/purchase'))
app.use('/api/v1/marketplace', require('./marketplace/coupons'))
app.use('/api/v1/marketplace', require('./marketplace/purchases'))

// Start server
let port = process.env.PORT
if (!port) {
    port = 5000
}
app.listen(port, () => {
    console.log(`Server started on ${port}!`)
})

A few things to keep in mind:

  • Make sure to setup cors() first
  • Setup express.json() (if you're using it) AFTER setting up the webhook route
  • Actually SEND a status rather than just setting res.status(200)

I just wasted half a day on this! Moving the express.json() to the bottom worked! Thanks

@fabriziospadaro
Copy link

That's how i solved it:

app.use((req, res, next) => { if (req.originalUrl.includes('YOUR_STRIPE_WEBHOOK')) { next(); } else { bodyParser.json()(req, res, next); } });

@Noushad-web
Copy link

I faced a similar issue and tried various approaches, including using body parser and exploring other options. Eventually, I discovered the Stripe GitHub examples repository, and its examples helped me resolve my issue.link

@TaseenRudra
Copy link

app.use('/api/v1/stripe/webhook', bodyParser.raw({ type: 'application/json' }));

add your specific url on it

@michaelboeding
Copy link

I ran into this issue also while using Google Cloud Functions. The link here helped me fix it : https://stackoverflow.com/questions/53899365/stripe-error-no-signatures-found-matching-the-expected-signature-for-payload

  1. Use req.rawBody
  2. Make sure you are using the right webhook secret which is listed in the stripe console and is specific to each web hook.

@oleksii-pi
Copy link

oleksii-pi commented Aug 8, 2024

I've killed half a day learning how it should work. My stack is Firebase, Express, TypeScript. I do not use any JSON parsing middleware, but req.body was always an object.

I ended up with this hack:

// index.ts:
const app = express();
app.use(express.json({
  verify: (req, res, buf) => {
    (req as any).rawBody = buf; // <<
  }
}));

const errorWrapper = (
  fn: (req: Request, res: Response, next: NextFunction) => Promise<void>
) => (req: Request, res: Response, next: NextFunction) => {
  Promise.resolve(fn(req, res, next)).catch(next);
};

app.post("/api/subscription/webhook", errorWrapper(webhook));

const errorHandler = (err: Error, req: Request, res: Response, next: NextFunction) => {
  console.error(err);
  const correlationId = req.headers["x-correlation-id"];
  res.status(500).json("Internal server error " + correlationId);
};

app.use(errorHandler);
// webhook.ts
import { Request, Response } from "express";
import { getStripeApi } from "./stripeapi";
import Stripe from "stripe";
import { defineSecret } from "firebase-functions/params";
export const STRIPE_WEBHOOK_SECRET_KEY = defineSecret("STRIPE_WEBHOOK_SECRET_KEY");

export const webhook = async (req: Request, res: Response) => {
  const sig = req.headers["stripe-signature"];
  if (sig === undefined) {
    console.error("Stripe signature is missing.");
    res.status(400).send("Stripe signature is missing.");
    return;
  }

  const stripe = getStripeApi();
  const webhookSecret = STRIPE_WEBHOOK_SECRET_KEY.value();

  let event: Stripe.Event;
  try {
    event = stripe.webhooks.constructEvent(req.rawBody, sig, webhookSecret);
  } catch (error) {
    console.error("Webhook signature verification failed.", error);
    res.status(400).send(`Webhook Error: ${(error as any).message}`);
    return;
  }

  //await handleEvent(event);

  res.json({ received: true });
};
// stripeapi.ts
import Stripe from "stripe";
import { defineSecret } from "firebase-functions/params";
export const STRIPE_SECRET_KEY = defineSecret("STRIPE_SECRET_KEY");

let stripeApi: Stripe | null = null;
export const getStripeApi = () => {
  return stripeApi ?? (stripeApi = new Stripe(STRIPE_SECRET_KEY.value(), { apiVersion: "2024-06-20" }));
};
// express.d.ts
import { Request } from "express";

declare module "express-serve-static-core" {
  interface Request {
    rawBody: Buffer; // <<
  }
}

@alexstyl
Copy link

The simplest thing that worked for me is to move the stripe webhook before using `app.use(bodyParser.json()):

const app = express();
app.use(cors())
app.post('/your-webhook-path', bodyParser.raw({type: '*/*'}), (request, response) => { 
    // the rest of the webhook
})
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));

@Fenil-v
Copy link

Fenil-v commented Dec 3, 2024

Good one this is more optimized solution as compare to getting static url of stripe hook and adding it in if else bloakc to it, you can also use express.raw instead of bodyparser it will work same.

@Samuel01111
Copy link

@alexstyl This works for me, after 10 hours at least, thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests