#mike7189-webhooks
1 messages · Page 1 of 1 (latest)
I am not understanding this stuff
here's the code of webhook, but I can't see anything like that in the console
./stripe listen --forward-to localhost:3001/api/webhook
seems alright, but I don't get it
okay I got the problem: it was /webhooks and not /webhook and I forgot break; in switch/case/default
so now this problem
okay you're making progress, now you get the event but you're apparently not parsing it properly. Did the constructEvent work? Because my guess is that you get an error. Log the event output first
nothing
event: undefined
this code gave undefined
server.use("/api/webhooks", express.raw({ type: "*/*" }), webhooksRouter); it's raw
not sure what "it's raw" means. You paste pictures of code and I'm not really following. Can you add logs? Like log the req.body, log the event after parsing it, confirm if you are getting in the catch, etc.
yep... it's not raw body
and if I remove express.raw({ type: "*/*" }), middlware - I am having body: undefined
Signature verification with Node/Express can be extremely painful: https://github.com/stripe/stripe-node/issues/341 has a lot of potential solutions
hold on a minute
if I don't use middlware it says body is undefined
if I use it shows me buffer
That's purely an Express question though, not really something Stripe specific
I am having rawParser middlware, body shown as Buffer, but signature verification fails anyway
is everythign alright over here?
@broken copper please avoid sharing pictures of code. You can share the exact code here between three ` on both sides
And I can't tell you if everything right, I've never used Express as a framework. This is something you need to debug on your end first since it's not really a Stripe issue just yet, it's about you not getting the raw body
also if you're just debugging, you can start without webhook signature verification to make progress and come back to this later
well I need a webhook now... Everything is pretty much done, I need to notify the website owner upon transaction
I kinda figured out what's the problem.
It's middleware. I do have rawParser and it's good, but typeof req.body gives me object, so apparently anonymous middleware is a json parser. God knows how to disable it
/* routes */
server.use("/api/webhooks", webhooksRouter);
server.use("/api", router);
weird stuff tho
yeah Express is super strange with this
I've seen at least 20 different solutions at this point, all subtly different 😦
typeof req.body should return Buffer, right?
I don't know sorry, that's an Express question, not related to Stripe's API 😅
it's not express question. It's about data type of raw body
I'm not sure I follow what you mean
the webhook has a line console.log(typeof req.body) what shall I expect on the output?
I do not know though
I've never played with Express, it's an Express thing, it's unrelated to Stripe, I don't know all the types in every languages I'm sorry
what would you expect in feathers or any other JavaScript library?
I'm really sorry, I'm not sure how to say it, I've never tried to print the type of that thing before in JS
body: {
id: 'evt_3JrQ7cKuBnFIZzDs1UVxRtd7',
object: 'event',
api_version: '2020-08-27',
created: 1635871564,
data: {
object: {
id: 'pi_3JrQ7cKuBnFIZzDs1x4Fh1Rv',
object: 'payment_intent',
amount: 7400,
amount_capturable: 0,
amount_received: 0,
application: null,
application_fee_amount: null,
canceled_at: null,
cancellation_reason: null,
capture_method: 'automatic',
charges: [Object],
client_secret: 'pi_3JrQ7cKuBnFIZzDs1x4Fh1Rv_secret_jeiiYx5FLvO6zsFevJrp4ZGDj',
confirmation_method: 'automatic',
created: 1635871564,
currency: 'eur',
customer: null,
description: null,
invoice: null,
last_payment_error: null,
livemode: false,
metadata: {},
next_action: null,
on_behalf_of: null,
payment_method: null,
payment_method_options: [Object],
payment_method_types: [Array],
receipt_email: null,
review: null,
setup_future_usage: null,
shipping: null,
source: null,
statement_descriptor: null,
statement_descriptor_suffix: null,
status: 'requires_payment_method',
transfer_data: null,
transfer_group: null
}
},
livemode: false,
pending_webhooks: 2,
request: {
id: 'req_Te3lQVnGSepvJq',
idempotency_key: '64bf9244-0e3c-43c0-8a82-5e5680036498'
},
type: 'payment_intent.created'
}
typeof body: object
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
event: undefined
so req.body seems to be readable now
yeah the problem is whether you are getting the real raw body
uhm... are you sure I need raw body and stripe.webhooks.constructEvent()?
I just passed it as JSON with const event = req.body and I got this:
event: {
id: 'evt_3JrQQHKuBnFIZzDs2RC8vROp',
object: 'event',
api_version: '2020-08-27',
created: 1635872721,
data: {
object: {
id: 'pi_3JrQQHKuBnFIZzDs2aZcXY9l',
object: 'payment_intent',
amount: 7400,
amount_capturable: 0,
amount_received: 0,
application: null,
application_fee_amount: null,
canceled_at: null,
cancellation_reason: null,
capture_method: 'automatic',
charges: [Object],
client_secret: 'pi_3JrQQHKuBnFIZzDs2aZcXY9l_secret_elkUTTwQwI5sCOBtLXRetjLkz',
confirmation_method: 'automatic',
created: 1635872721,
currency: 'eur',
customer: null,
description: null,
invoice: null,
last_payment_error: null,
livemode: false,
metadata: {},
next_action: null,
on_behalf_of: null,
payment_method: null,
payment_method_options: [Object],
payment_method_types: [Array],
receipt_email: null,
review: null,
setup_future_usage: null,
shipping: null,
source: null,
statement_descriptor: null,
statement_descriptor_suffix: null,
status: 'requires_payment_method',
transfer_data: null,
transfer_group: null
}
},
livemode: false,
pending_webhooks: 2,
request: {
id: 'req_bF0QtDVtdCoSdx',
idempotency_key: 'b7ca3af9-e654-4aa3-b86d-33dd45a7f98e'
},
type: 'payment_intent.created'
}
webhooksRouter.post(
"/",
express.json({ type: "application/json" }),
async (req, res) => {
const event = req.body;
try {
console.log(`body: `, req.body);
console.log(`headers: `, req.headers);
} catch (error) {
console.log(`error: `, error.message);
} finally {
console.log("finally:");
console.log(`event type: `, event.type);
}
}
);
just like this
https://stripe.com/docs/webhooks#webhook-endpoint-code
here it specifically says to parse JSON
that code example is explicitly not verifying signatures though
few months back I had the same problem, and I think I was talking to you and we had kinda same discussion and I "solved" the issue by adding express.raw({type:"*/*"}) middleware to the route and it was working just fine.
Today I finally got back to my old project, and all of a sudden webhook stopped working
https://stripe.com/docs/webhooks/signatures#verify-official-libraries
ah I see here with verification
so... is there anything bad about not verifying signature?
Well it means someone can "attack" your integration and send fake events. What you could do to start is call https://stripe.com/docs/api/events/retrieve to retrieve the Event from the API and make sure it's valid. It's more API Requests but it might help to start
hm....
So in webhook upon each event I can call retrieve() and
if (event_in_webhook !== event_in_retrieve) throw new Error(403)
right?
you don't need the diff at all. Just get the id from the payload then call https://stripe.com/docs/api/events/retrieve and process that Event
ignore the rest of the webhook body
so:
if (event_in_webhook.id !== event_in_retrieve.id) throw new Error(403)
?
not at all no
You get the Event's JSON already. I explained you can't trust it, unless you verify the signature. So instead you ignore the entire JSON other than the event id the evt_123. Then your call does a call to https://stripe.com/docs/api/events/retrieve and then you handle the event based on the response the API gives you, you ignore the rest
oh.. So all I need is to handle the last event? charge_succeeded or something like that?
and if event is malicious, this event wont exist on retrieve(), right?
correct, or the data they will send you will ignore
imagine someone finding a way to pay $1 but tell you they paid $222.22 by sending amount: 22222 in the Event, you would ignore it, retrieve it from the API itself and see amount: 100
damn i am lost
Yeah sorry, I'm just not understanding what part is losing you unfortunately
All you have to do is this
1/ Something happens in your account
2/ Stripe creates an Event and sends the JSON to your endpoint/code
3/ Your code gets it, gets the event id (evt_123) and then ignores everything else
4/ Your code calls https://stripe.com/docs/api/events/retrieve and then handles the event, the same way as if you used the payload/JSON we sent you
Alright. I’ll try to verify normal way, if I won’t manage it I’ll go with events stuff
sounds good
event: {
id: 'evt_3JrSTHKuBnFIZzDs1nD3x3kX',
object: 'event',
api_version: '2020-08-27',
created: 1635880596,
data: {
object: {
id: 'pi_3JrSTHKuBnFIZzDs1luoc5pQ',
object: 'payment_intent',
amount: 7400,
amount_capturable: 0,
amount_received: 0,
application: null,
application_fee_amount: null,
canceled_at: null,
cancellation_reason: null,
capture_method: 'automatic',
charges: [Object],
client_secret: 'pi_3JrSTHKuBnFIZzDs1luoc5pQ_secret_l2RvQLif1gcatDKRgJC6uqPMy',
confirmation_method: 'automatic',
created: 1635880595,
currency: 'eur',
customer: null,
description: null,
invoice: null,
last_payment_error: null,
livemode: false,
metadata: {},
next_action: null,
on_behalf_of: null,
payment_method: null,
payment_method_options: [Object],
payment_method_types: [Array],
receipt_email: null,
review: null,
setup_future_usage: null,
shipping: null,
source: null,
statement_descriptor: null,
statement_descriptor_suffix: null,
status: 'requires_payment_method',
transfer_data: null,
transfer_group: null
}
},
livemode: false,
pending_webhooks: 2,
request: {
id: 'req_zMieJIWMvNaHbN',
idempotency_key: '11edd702-edac-4bd4-adc8-fe5d71c450a0'
},
type: 'payment_intent.created'
}
jesus christ I did it
https://github.com/stripe/stripe-node/issues/341#issuecomment-757394040
keep the link, I hope it'll help some other express user 😄
server.use("/api/webhooks", express.raw({ type: "*/*" }), webhooksRouter);
server.use("/api", express.json(), router);
raw before json and that's it. It seems. I dunno, I've tried so much stuff, I have no damn clue what I've actually done
damn
yeah I told you there are so many weird answers in that issue
thanks for taking the time to post it on that link, it will help others, I really appreciate it
and congrats, this is no small feat to make this work with node+Express trust me
As far as I understood the biggest issue is that express.json() making a mess.
Thank you for your time 😇