#mac - signature verification

1 messages · Page 1 of 1 (latest)

sullen galleon
#

Hi there. One moment

hybrid citrus
#
  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,
            }
          }
        )
sullen galleon
#

You can't pass fake data into constructEvent

#

It will only work with real data

#

It's checked serverside with stripe

hybrid citrus
sullen galleon
#

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?

hybrid citrus
#
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.

sullen galleon
hybrid citrus
#

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?

sullen galleon
#

Oh you're using the real one?

#

I think you need to use const secret = 'whsec_test_secret';

hybrid citrus
#

Same issue

unreal bridge
#

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?

hybrid citrus
#

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 😛

unreal bridge
#

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.

hybrid citrus
#

That looks to be exactly what generateTestHeaderString is doing

unreal bridge
#

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.

hybrid citrus
#

Checking

unreal bridge
#

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.

hybrid citrus
#

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

unreal bridge
#

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?

unreal bridge
#

Any luck?

hybrid citrus
#

I think the issue is that I needed to set Content-Type to application/json but stringify the request body as was suggested earlier

unreal bridge
#

Ah, did you get it working?

hybrid citrus
#

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: {}
rocky radish
#

awesome!

hybrid citrus
#

Thank you for all the help!