#mac - signature verification
1 messages · Page 1 of 1 (latest)
const fakeWebHookEvent = {
id: '123',
object: 'event',
api_version: '',
created: 2,
livemode: false,
pending_webhooks: 2,
request: {
id: '123',
idempotency_key: '123',
},
type: 'fake_event.succeeded',
data: {
object: {
metadata: {
userId: userId as any,
tenantId: process.env.STRIPE_API_TENANT_ID,
},
status: 'succeeded',
},
},
}
const fakeStripeSignature = stripe.webhooks.generateTestHeaderString({
payload: JSON.stringify(fakeWebHookEvent),
secret: stripeEnvVariables.WEBHOOK_SECRET_KEY_LOCAL_OVERRIDE,
})
axios.post(
'http://0.0.0.0:3000/payment/webhook',
fakeWebHookEvent,
{
headers: {
'stripe-signature': fakeStripeSignature,
}
}
)
You can't pass fake data into constructEvent
It will only work with real data
It's checked serverside with stripe
That's what I thought... But what is constructEvent doing in this scenario then?https://github.com/stripe/stripe-node#testing-webhook-signing
Oh interesting... I'm not as familiar with our node library as others so I didn't know we had that until now. I would need to see more of your code, but stripe.webhooks.generateTestHeaderString just creates the header. Looks like you named the variable fakeStripeSignature
Can you share the piece of code where you call constructEvent?
const sig = req.headers['stripe-signature']!
const webhookSecretKey = envVariables.STRIPE_API.WEBHOOK_SECRET_KEY_LOCAL_OVERRIDE
event = stripe.webhooks.constructEvent(req.rawBody!, sig, webhookSecretKey)
Note that everything works fine when it comes to receiving events from cli trigger, etc.
Gotcha. Try passing in JSON.stringify around fakeWebhookEvent here: axios.post(
'http://0.0.0.0:3000/payment/webhook',
fakeWebHookEvent,
Stringifying the request unfortunately doesn't match up with the request body format that stripe sends so it's failing my endpoint parameter validation
The webhook endpoint is correctly getting the request in the same format as as when stripe sends an event, aka rawBody is a string of the request
Should I try using a fake webhook secret key and not a real test one?
Oh you're using the real one?
I think you need to use const secret = 'whsec_test_secret';
Same issue
Hello! Taking over and catching up...
To clarify, you're trying to create an arbitrary/test event payload and manually sign it properly so you can then use constructEvent to verify the signature?
If so, have you read this section of our docs? https://stripe.com/docs/webhooks/signatures#verify-manually
Correct. Basically I'm trying to integration test our stripe endpoint, which includes test cases which have successful and unsuccessful stripe signature verifications
I've seen it but given there was a non-manual way to verify a signature I thought that would be the preferred route
Essentially trying to avoid having to do "if integ test, don't have Stripe verify signature"
Also happy to set up a call or something with someone to dive into this. This is for a product at DoorDash so let me know if I should attempt to go through another channel of communication instead. This discord is just more responsive as far as dev help goes than having to go through our TAM to get a response from a dev via our shared slack channel 😛
Gotcha. So that section I linked to above talks about how you can manually verify signatures without using our libraries, which is not what you're doing, but in doing so it also explains how the signatures are generated, which is what you're trying to do. If you read through that you should be able to then generate signatures on your end which our libraries will then be able to verify.
That looks to be exactly what generateTestHeaderString is doing
Looking...
Ah, yep, it is.
Is the payload you're feeding to that exactly the same as the one you're feeding to constructEvent? They have to be identical, including whitespace and everything.
Checking
Looking at the code you shared above it looks like you're passing JSON.stringify(fakeWebHookEvent) to the generateTestHeaderString function, but you're passing fakeWebHookEvent to axios. My guess is axios is doing something different than JSON.stringify is. That or there's some middleware somewhere altering the body of the request.
Hard for me to tell, if everything else is working correctly than that's probably the issue. Need to dig around to see if anyone else has any examples of properly stringifying -> properly parsing w middleware -> constuctEvent
Can you see the raw output of the HTTP request coming from axios? Can you diff that with the output of JSON.stringify and see how they differ?
Any luck?
I think the issue is that I needed to set Content-Type to application/json but stringify the request body as was suggested earlier
Ah, did you get it working?
Yes just did!
const fakeStripeSignature = stripe.webhooks.generateTestHeaderString({
payload: JSON.stringify(fakeWebHookEvent, null, 2),
secret: 'whsec_test_secret',
})
axios.post(
'http://0.0.0.0:3000/payment/webhook',
JSON.stringify(fakeWebHookEvent, null, 2),
{
headers: {
'stripe-signature': fakeStripeSignature,
'Content-Type': 'application/json',
},
}
)
webhookSecretKey = 'whsec_test_secret'
event = stripe.webhooks.constructEvent(req.rawBody!, sig, webhookSecretKey)
/payment/webhook:
post:
summary: HandlePaymentWebook
description: Handle payment webhook events from stripe. This endpoint should not be directly interacted with and instead you should use the Stripe CLI or Dashboard
operationId: HandlePaymentWebook
parameters:
- in: header
name: stripe-signature
schema:
type: string
required: true
requestBody:
content:
application/json:
schema:
required:
- id
- object
- api_version
- created
- data
- livemode
- pending_webhooks
- request
- type
type: object
required: true
description: Request body for Stripe webhook events.
responses:
'200':
description: Successful receipt of the webhook event
headers: {}
awesome!
The interaction between json, strings, buffers etc is a bit confusing overall. I think an example of actually using a fake event to trigger a webhook would be a good add to https://github.com/stripe/stripe-node/tree/master/examples/webhook-signing as a test case
Thank you for all the help!