I am building a web application with a login form and stripe subscription functionality.
In order to receive JSON data I am using express.json
as
app.use(express.json());
When I was using the above middleware to receive stripe webhook secret
the server could not receive it.
So I had to add the express.raw
My middleware looked like this:
app.use(express.raw({ type: "application/json" }));
app.use(express.json());
But now I am unable to receive form JSON data.
Here is my stripe logic:
export const postStripeWebhook = async (req: ExtendedRequest, res: Response) => {
let data;
let eventType;
let event = req.body;
const webhookSecret = "web hook secret provided by stripe";
if (webhookSecret) {
let signature = req.headers["stripe-signature"];
try {
event = stripe.webhooks.constructEvent(req.body, signature , webhookSecret);
} catch (err) {
console.log(`⚠️ Webhook signature verification failed.`); //This part is throwing the error
return res.sendStatus(400);
}
data = event.data;
eventType = event.type;
} else {
data = req.body.data;
eventType = req.body.type;
}
let subscription;
switch (eventType) {
// Here webhook events are managed
}
res.sendStatus(200);
};
Here is the index.js code:
app.use(express.raw({ type: "application/json" }));
app.use(express.json());
app.use(express.static("public"));
app.use(express.urlencoded({ extended: true }));
app.use(cors());
app.post("/webhooks", postStripeWebhook);
Updated code-------------------------
index.js:
app.use(express.json());
app.use(express.static("public"));
app.use(express.urlencoded({ extended: true }));
app.use(cors());
app.post("/webhooks", postStripeWebhook);
Middleware code:
export const postStripeWebhook = async (req: ExtendedRequest, res: Response) => {
let data;
let eventType;
let event = req.body;
const webhookSecret = "web hook secret provided by stripe";
if (webhookSecret) {
let signature = req.headers["stripe-signature"];
try {
event = stripe.webhooks.constructEvent(JSON.stringify(req.body), signature , webhookSecret); //updated this line
} catch (err) {
console.log(`⚠️ Webhook signature verification failed.`); //This part is throwing the error
return res.sendStatus(400);
}
data = event.data;
eventType = event.type;
} else {
data = req.body.data;
eventType = req.body.type;
}
let subscription;
switch (eventType) {
// Here webhook events are managed
}
res.sendStatus(200);
};
I updated the code but still, but the problem persists.
Please guide me on how to modify my middleware to receive both types of data.
CodePudding user response:
It depends on your needs
you can add the bodyParser.json()
as a middleware in your api
For example: app.post('/some/special/route/accepts_as_json', bodyParser.json() , (req,res)=>{} )
Then leave the app.use(express.raw({ type: "application/json" }));
on your index, if you don't mention the middleware it will be raw, if you do mention is you will receive the jsons
CodePudding user response:
You don't need express.raw
, only express.json
. This parses JSON requests and stores the resulting Javascript object in req.body
. However, if you want to send this object to stripe.webhooks.constructEvent
, you must stringify it again:
stripe.webhooks.constructEvent(JSON.stringify(req.body), sig, endpointSecret)
Without the JSON.stringify
, you would send [object Object]
, which is not understood by Stripe and leads to the observed error.
express.raw({type: "application/json"})
writes the JSON to req.body
as a string, but this is not useful except for your special case, therefore I would not use it. However, if the Stripe signature depends on the exact string format of the JSON payload (which I would find strange), then you cannot avoid this. In this case, you should follow Ibrahim shamma's suggestion but put the Stripe middleware before the express.json()
:
app.post("/webhooks", express.raw({type: "application/json"}), postStripeWebhook);
app.use(express.json());
app.use(express.static("public"));
app.use(express.urlencoded({ extended: true }));
app.use(cors());
This ensures that the "raw parsing" happens only for POST /webhooks
requests, all others can still be parsed as normal JSON.