#yen-webhook-node

1 messages ยท Page 1 of 1 (latest)

copper ginkgoBOT
smoky garnet
#

Hi

rain hearth
#

Hello! Can you show me screenshots of exactly what you're seeing where it says it's succeeed and where you're seeing the 400 POST error

smoky garnet
#

Yeah ofcourse

#

Got to see this logs after doing this stripe listen --forward-to localhost:3000/api/stripe/webhook

rain hearth
#

And where are you seeing that the events succeeded?

smoky garnet
#

2023-08-17 17:40:12 --> charge.succeeded [evt_3Ng8IrD7Shm9DtKO1c1vjT9m]

#

Doesnt that mean that the charge has succeeded?

#

Before i didn't get to see charge.succeeded

#

I only saw the 400 errors

#

But ive changed my code and now it shows me this

#

Ah no i am wrong

#

The charge.succeeded event works so I think that's why I am seeing that?

rain hearth
#

Let's back up for a second - the 400 errors are specifically for responding to the webhook event (as in we send the event to the endpoint you specified but we didn't get a response back). That doesn't prevent from charges from succeeding

smoky garnet
#

Ah alright

#

In my server.js file I logged the signature const signature = req.headers['stripe-signature'];

#

Which logged my signature

#

Before signature logged undefined

#

But when logging this event = stripe.webhooks.constructEvent(buf, signature, webhookSecret); it returns undefined

rain hearth
#

Have you logged the webhoookSecret and buf to confirm they're what you expect?

#

Also just to make sure - your issue right now is that you're trying to get signature verification to work and see 200 successful responses from your webhook endpoint, right?

smoky garnet
#

Yes, I think the problem might be the buf

#

And yes, i want to see a 200 succesfull response,

#

But I am not even sure what is expected from a buf

#

This is a piece of my webhook code:

export default async function handler(req, res) {

    const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

    const buf = await buffer(req);
    const signature = req.headers['stripe-signature'];
    const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;

    let event;

    try {
        // if(!signature || !webhookSecret) return;

        event = stripe.webhooks.constructEvent(buf, signature, webhookSecret);
        res.status(200).send('OK');

    } catch(error) {
        console.log(event);
        return res.status(400).send(`Webhook error: ${error.message}`);
    }
#

So buf is my request, but I found out that the request body is not raw

#

And Stripe expects a raw request body right?

rain hearth
#

Yeah, for signature revification we definitely need the raw request body

smoky garnet
#

Ah okay

#

Can i show the output of the bug variable?

#

Because webhookSecret and the signature have the correct data

#

I've checked it

#

webhook secret logs this:
we_1NdcdMD...

signature:
t=1692229813,v1=efdffe399709232d32134cc073cf4d8d4af16923df489852df1238156c5bf906fc,v0=be491312321e5c35135ae40126692726ffeed83b9630e20596f8b66c90a7059910e51a8

rain hearth
#

Yup feel free to share the buf

#

Also your webhook secret isn't correct

#

It should be seomthing like whsec_123

#

and you should get it from your stripe listen command

smoky garnet
#

oh really.. oops my bad

#

Well here is my buf:

{
  "id": "evt_3Ng96jD7Shm9DtKO1KkBRxwZ",
  "object": "event",
  "api_version": "2022-11-15",
  "created": 1692289897,
  "data": {
    "object": {
      "id": "pi_3Ng96jD7Shm9DtKO157pqBf4",
      "object": "payment_intent",
      "amount": 200,
      "amount_capturable": 0,
      "amount_details": {
        "tip": {
        }
      },
      "amount_received": 0,
      "application": null,
      "application_fee_amount": null,
      "automatic_payment_methods": {
        "allow_redirects": "always",
        "enabled": true
      },
      "canceled_at": null,
      "cancellation_reason": null,
      "capture_method": "automatic",
      "client_secret": "pi_3Ng96jD7Shm9DtKO157pqBf4_secret_vfKDez34w113H5vzniQWqWI3C",
      "confirmation_method": "automatic",
      "created": 1692289897,
      "currency": "eur",
      "customer": null,
      "description": null,
      "invoice": null,
      "last_payment_error": null,
      "latest_charge": null,
      "livemode": false,
      "metadata": {
      },
      "next_action": null,
      "on_behalf_of": null,
      "payment_method": null,
      "payment_method_options": {
        "card": {
          "installments": null,
          "mandate_options": null,
          "network": null,
          "request_three_d_secure": "automatic"
        }
      },
      "payment_method_types": [
        "card"
      ],
      "processing": null,
      "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_kp6x7vO2PyH5up",
    "idempotency_key": "7661f9a6-4636-46c8-9b8f-e6185541bf75"
  },
  "type": "payment_intent.created"
}
#

So the problem is my webhook secret?

#

I get my webhook secret from the .env file in my project

#

So i just pasted the secret in the .env and then accessed it like this ```
const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;

let event;

try {
    // if(!signature || !webhookSecret) return;

    event = stripe.webhooks.constructEvent(buf, signature, webhookSecret);
    res.status(200).send('OK');

``

#

Could you elaborate this? and you should get it from your stripe listen command because I know this command can be used in the terminal. But I don't really understand how I could implement this in my code

rain hearth
#

While you're testing things out with the stripe CLI you typically use the stripe listen command, which works different than normal webhook endpoints and needs it's own webhook secret

#

Once you're ready to go to production you'd create a real webhook endpoint (through the dashboard or API) and that would give you a new webhook secret that you'd use in your code

smoky garnet
#

Oooh, now I finally understand

#

It works locally (get a 200 response), but on production I still get a 400 error

#

And I have hosted my Next.js project with Vercel

rain hearth
#

It's likely that in production you're using the wrong webhook endpoint secret then

smoky garnet
#

The webhook endpoint secret also starts with whsec right?

#

I found it under 'Signing secret'

#

And I have added that to Vercel's environment variables

rain hearth
#

Yup it should also start with whsec

#

are you still getting errors after confirming that's correct

#

Is it still not working?

smoky garnet
#

Yes, I still get the 400 error

#

But only on production

rain hearth
#

Can you do the same logging you did locally for production and confirm you're seeing the right things?

smoky garnet
#

Yes, one sec please!

#

I'll show you the error first:

StripeSignatureVerificationError: No stripe-signature header value was provided.
    at parseEventDetails (file:///var/task/node_modules/stripe/esm/Webhooks.js:103:19)
    at Object.verifyHeader (file:///var/task/node_modules/stripe/esm/Webhooks.js:65:102)
    at Object.constructEvent (file:///var/task/node_modules/stripe/esm/Webhooks.js:10:32)
    at handler (/var/task/.next/server/pages/api/stripe/webhook.js:53:29)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
  type: 'StripeSignatureVerificationError',
  raw: { message: 'No stripe-signature header value was provided.' },
  rawType: undefined,
  code: undefined,
  doc_url: undefined,
  param: undefined,
  detail: undefined,
  headers: undefined,
  requestId: undefined,
  statusCode: undefined,
  charge: undefined,
  decline_code: undefined,
  payment_intent: undefined,
  payment_method: undefined,
  payment_method_type: undefined,
  setup_intent: undefined,
  source: undefined,
  header: undefined,
  payload: <Buffer 7b 22 65 76 65 6e 74 22 3a 22 63 68 61 72 67 65 2e 63 61 70 74 75 72 65 64 22 7d>
}
rain hearth
#

Interesting... so looks like there are issues with egetting the stripe-signature header on your production server

copper ginkgoBOT
smoky garnet
#

buf:
<Buffer 7b 22 65 76 65 6e 74 22 3a 22 63 68 61 72 67 65 2e 63 61 70 74 75 72 65 64 22 7d>

signature:
undefined

webhookSecret:
whsec_rC0tLaZSs4b4Z9Dsv6kTD8ePBheBF28I

#

The buf looks off

waxen solar
smoky garnet
#

Helloe

waxen solar
#

HEllo! Sorry for the delay, Discord is really busy right now and I'm catching up on many other threads

#

I don't really understand your question overall unfortunately

#

yen-webhook-node

smoky garnet
#

Hmm, but I don't get why I should start over because everything works locally? The 400 error only occurs on production

#

And no problem

waxen solar
#

The problem is that Node.js makes this extremely hard if you don't do this right or have a different environment between dev and prod

#

I often recommend carefully reading through https://github.com/stripe/stripe-node/issues/356 to find the right configuration as it depends on your Node.js version, the framework you're using, third-party libraries, etc. It's really finicky sadly ๐Ÿ˜ฆ

smoky garnet
#

๐Ÿ˜ฆ

#

Would it help to switch to another hosting platform?

#

And I am going to check your github link

waxen solar
#

I can't tell you, right now the next step is to carefully read through some of those comments and figure out what's different between your local/dev environment and your production environment

smoky garnet
#

My local/dev environment is not different from my production environment tho

#

Only thing thats different are the data in my .env file

waxen solar
#

I mean something is different, otherwise it'd work right?

#

Like signature: undefined this isn't a Stripe issue, it's your code

#

You need to dump the raw header of the HTTP request you get to figure out what's happening

#

something is removing access to that header somewhere in your code/environment right?

copper ginkgoBOT
smoky garnet
#

Okay, thanks for helping me though

#

Im actually working for a person who doesn't have knowledge about coding, but I am building a webshop for him and I am an intern

#

And he keeps asking me if I can solve it faster

#

And if there are better and faster ways to host this

#

Could any of u guys write something for me so I can show some proof that it's not easy to solve? Like i have to do some research and experiment to find out whats going wrong ๐Ÿ˜ฆ

waxen solar
#

No we can't sorry

smoky garnet
#

Oh okay

#

No problem

waxen solar
#

My advice: you can skip signature verification entirely

#

that should mostly do it while you figure out signature verification later

#

I have to run, but at least that would unblock you. Signature verification is not a requirement it's just recommend for security reasons

smoky garnet
#

Thats okay,