PaddleHQ / paddle-node-sdk

Node.js SDK for working with the Paddle API in server-side apps.
https://developer.paddle.com/
Apache License 2.0
42 stars 6 forks source link

[Bug]: Webhook time validation error #30

Closed Abel1011 closed 4 months ago

Abel1011 commented 4 months ago

What happened?

Hi,

Thank you for the library. Recently, I have been having a problem validating the webhook signature: it was working fine a few days ago, but now it rejects all requests. I have checked the details and see that the failure occurs in this date-related code. I would like to know if there has been any recent change in the webhook functionality.

Steps to reproduce

Simply test the webhook in sandbox mode.

What did you expect to happen?

webhooks-validator.ts

Verify that it fails to validate the date; if the MAX_VALID_TIME_DIFFERENCE is increased from 5 to 10 it works normally.

Logs

No response

vijayasingam-paddle commented 4 months ago

Hi @Abel1011 , Thank you for reaching out to us. I can confirm that there has been no change to the webhook functionality.

Ideally, we expect our users to follow the below steps,

  1. Receive the webhook
  2. Validate its integrity
  3. Start their processing - Synchronous or Asynchronous based on how long they need
  4. Respond to us with a success code.

We expect them to complete this within 5 seconds of receiving it. If we have not received a success code by then, we will mark the event as failed.

Due to this, updating the validation to wait for 10 seconds will not solve the problem

I tried to replicate this in our test environment and I did not see any issues. Can you please share a reproducible example or more information on how you are processing webhooks so that we can check further?

Thank you.

Abel1011 commented 4 months ago

Hello, thank you for responding. I am using the same example, but I am using next.js.

Here are some debugging logs. This is the body I receive: {"data":{"id":"sub_01hygaydyp1cnen0ch4pcmn2hw","items":[{"price":{"id":"pri_01hva6ws5azj9ss38k0fat3hmd","name":"Monthly","type":"standard","status":"active","quantity":{"maximum":1,"minimum":1},"tax_mode":"account_setting","seller_id":"7721","created_at":"2024-04-12T22:29:48.330553Z","product_id":"pro_01hva6swd8gzdref1ynp7aehej","unit_price":{"amount":"1200","currency_code":"USD"},"updated_at":"2024-05-06T22:45:00.18598Z","custom_data":null,"description":"Plan Mensual","import_meta":null,"trial_period":null,"billing_cycle":{"interval":"day","frequency":1},"unit_price_overrides":[]},"status":"active","quantity":1,"recurring":true,"created_at":"2024-05-22T14:23:08.758Z","updated_at":"2024-05-22T14:23:08.758Z","trial_dates":null,"next_billed_at":"2024-05-23T14:23:07.986583Z","previously_billed_at":"2024-05-22T14:23:07.986583Z"}],"status":"active","discount":null,"paused_at":null,"address_id":"add_01hygaxybc1sd2qh2cgcbas0q4","created_at":"2024-05-22T14:23:08.758Z","started_at":"2024-05-22T14:23:07.986583Z","updated_at":"2024-05-22T14:23:08.758Z","business_id":null,"canceled_at":null,"custom_data":{"name":"Organismos Reguladores","email":"organismos.reguladores.loreto@gmail.com","userId":2},"customer_id":"ctm_01hvevwbm5s2fb9st3mxsp88rq","import_meta":null,"billing_cycle":{"interval":"day","frequency":1},"currency_code":"USD","next_billed_at":"2024-05-23T14:23:07.986583Z","transaction_id":"txn_01hygaxw4m1adfwvm4j9pnmca4","billing_details":null,"collection_mode":"automatic","first_billed_at":"2024-05-22T14:23:07.986583Z","scheduled_change":null,"current_billing_period":{"ends_at":"2024-05-23T14:23:07.986583Z","starts_at":"2024-05-22T14:23:07.986583Z"}},"event_id":"evt_01hygayed5crjtag84eyt3apds","event_type":"subscription.created","occurred_at":"2024-05-22T14:23:09.221955Z","notification_id":"ntf_01hygayeg551y13kvhpx8dpm7j"}

The signature: ts=1716388180;h1=a7a9babbccc93c1868e4e0f53a79ccadcb7591a2bbca062c2e9c7976060ff935

When I run unmarshal, I get this error: [Paddle] Webhook signature verification failed;

I have tried to debug why this error occurs and I found that it fails here:

if (new Date().getTime() > new Date((headers.ts + WebhooksValidator.MAX_VALID_TIME_DIFFERENCE) * 1000).getTime()) { return false; }

I did a console.log of the values and for new Date().getTime() I got 1716388188701 and for the second value I got 1716388185000; therefore, it returns false and does not validate the value; that's why I suggested increasing the value of MAX_VALID_TIME_DIFFERENCE.

The truth is that it worked fine before, but now I don't know why it's failing.

vijayasingam-paddle commented 4 months ago

Hi @Abel1011, Thank you for providing an example.

At close examination of the timeline, I can see that it took 8 seconds since the event was sent to reach your first console.log. This is not normal and it could be the root cause of your problem.

We also noticed that you are using localtunnel to listen to the events. There is a very good chance that it is delayed because of the tunnel. Can you please try to run your code from a remote server?

We can improve the local development experience by skipping the time check. We are considering some improvements in this area as part of a different ticket(#28).

Thank you.

Abel1011 commented 4 months ago

Hello, thank you for your reply. As you indicated, it appears to be a tunnel problem. I deployed on Vercel, and the webhook was received and processed without any issues. Thank you for your help. Regards.

vijayasingam-paddle commented 4 months ago

Hello, I am glad your issue is resolved.

Please feel free to reach out to us if you need any other help.