Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deployed functions rawBody failing Stripe validation #2099

Closed
wollerman opened this issue Jul 6, 2023 · 4 comments
Closed

Deployed functions rawBody failing Stripe validation #2099

wollerman opened this issue Jul 6, 2023 · 4 comments
Labels
bug Something isn't working

Comments

@wollerman
Copy link
Contributor

I'm working on setting up a stripe integration which requires access to the raw body of the request. I've followed the steps outlined in #770

These steps work locally. However, once deployed, the stripe signature validation fails.

To Reproduce
Steps to reproduce the behavior:

  1. Create a function that tries to parse rawBody. In this case, ideally with stripe's stripe.webhooks.constructEvent function
  2. Set up the local stripe CLI to send payloads (this works as expected)
  3. Deploy the function to nhost cloud
  4. Send a test (or real) payload from stripe to the webhook
  5. This fails with:

{"log":"y8 [Error]: No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe? \nLearn more about webhook signing and explore webhook integration examples for various frameworks at https://github.com/stripe/stripe-node#webhook-signing\n at n (/var/task/lambda.js:272:158)\n at Object.verifyHeader (/var/task/lambda.js:270:32559)\n at Object.constructEvent (/var/task/lambda.js:270:31617)\n at qne (/var/task/lambda.js:273:6113)\n at Ln.handle_request (/var/task/lambda.js:30:3792)\n at p (/var/task/lambda.js:30:5835)\n at p (/var/task/lambda.js:30:5802)\n at p (/var/task/lambda.js:30:5802)\n at p (/var/task/lambda.js:30:5802)\n at p (/var/task/lambda.js:30:5802) {\n type: 'y8',\n raw: {\n message: 'No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe?

Expected behavior
The webhook parses rawBody correctly when deployed

Additional context
I've added full body examples here: #770 (reply in thread)

@wollerman wollerman added the bug Something isn't working label Jul 6, 2023
@wollerman wollerman changed the title Deployed functions rawBody not working as expected Deployed functions rawBody failing Stripe validation Jul 6, 2023
@dbarrosop
Copy link
Contributor

I'd suggest you to console.log locally and in the cloud and compare if there are any differences.

@wollerman
Copy link
Contributor Author

To test locally with Stripe I set up the local forwarder. Here's the output of initializing and when making successful round trip requests to my nhost function that it forwards to:

❯ stripe listen --forward-to https://local.functions.nhost.run/v1/payment/stripe_hook
> Ready! You are using Stripe API Version [2022-11-15]. Your webhook signing secret is **redacted** (^C to quit)
2023-07-08 08:23:49   --> payment_intent.created [evt_3NRaAzKE0B3nGMSO0ciK9GxH]
2023-07-08 08:23:49  <--  [200] POST https://local.functions.nhost.run/v1/payment/stripe_hook [evt_3NRaAzKE0B3nGMSO0ciK9GxH]
2023-07-08 08:23:53   --> payment_intent.succeeded [evt_3NRaAzKE0B3nGMSO0wwPGlPE]
2023-07-08 08:23:53  <--  [200] POST https://local.functions.nhost.run/v1/payment/stripe_hook [evt_3NRaAzKE0B3nGMSO0wwPGlPE]
2023-07-08 08:23:53   --> charge.succeeded [evt_3NRaAzKE0B3nGMSO0qXI3dEO]
2023-07-08 08:23:53  <--  [200] POST https://local.functions.nhost.run/v1/payment/stripe_hook [evt_3NRaAzKE0B3nGMSO0qXI3dEO]

Below are the logs from the function printing the following lines locally:

const sig = request.headers["stripe-signature"] as string;
console.log(sig);
console.log("rawBody:");
console.log(request.rawBody);

nhost-api-functions-1  | POST /payment/stripe_hook 200 - - 18.825 ms
nhost-api-functions-1  | t=1688819033,v1=1352785f9c3d953997f35b6418c49312613a9edf767d02e3c1359389fca16aee,v0=baca6be05c23934c2e812a5b2c8bd2a3e1b824f86c563ccd8683c4e70f4a2f81
nhost-api-functions-1  | rawBody:
nhost-api-functions-1  | {
nhost-api-functions-1  |   "id": "evt_3NRaAzKE0B3nGMSO0wwPGlPE",
nhost-api-functions-1  |   "object": "event",
nhost-api-functions-1  |   "api_version": "2022-11-15",
nhost-api-functions-1  |   "created": 1688819033,
nhost-api-functions-1  |   "data": {
nhost-api-functions-1  |     "object": {
nhost-api-functions-1  |       "id": "pi_3NRaAzKE0B3nGMSO0nwftizJ",
nhost-api-functions-1  |       "object": "payment_intent",
nhost-api-functions-1  |       "amount": 299,
nhost-api-functions-1  |       "amount_capturable": 0,
nhost-api-functions-1  |       "amount_details": {
nhost-api-functions-1  |         "tip": {
nhost-api-functions-1  |         }
nhost-api-functions-1  |       },
nhost-api-functions-1  |       "amount_received": 299,
nhost-api-functions-1  |       "application": null,
nhost-api-functions-1  |       "application_fee_amount": null,
nhost-api-functions-1  |       "automatic_payment_methods": {
nhost-api-functions-1  |         "allow_redirects": "always",
nhost-api-functions-1  |         "enabled": true
nhost-api-functions-1  |       },
nhost-api-functions-1  |       "canceled_at": null,
nhost-api-functions-1  |       "cancellation_reason": null,
nhost-api-functions-1  |       "capture_method": "automatic",
nhost-api-functions-1  |       "client_secret": "pi_3NRaAzKE0B3nGMSO0nwftizJ_secret_J6htv5i5RTYfDRmgmNbQIuULb",
nhost-api-functions-1  |       "confirmation_method": "automatic",
nhost-api-functions-1  |       "created": 1688819029,
nhost-api-functions-1  |       "currency": "usd",
nhost-api-functions-1  |       "customer": "cus_O4UuYZ8WOom6OJ",
nhost-api-functions-1  |       "description": "10 token(s)",
nhost-api-functions-1  |       "invoice": null,
nhost-api-functions-1  |       "last_payment_error": null,
nhost-api-functions-1  |       "latest_charge": "ch_3NRaAzKE0B3nGMSO0b8ljNAF",
nhost-api-functions-1  |       "livemode": false,
nhost-api-functions-1  |       "metadata": {
nhost-api-functions-1  |         "tokens": "10",
nhost-api-functions-1  |         "userId": "e265349c-6fe9-471a-b68c-a700cffa22ee"
nhost-api-functions-1  |       },
nhost-api-functions-1  |       "next_action": null,
nhost-api-functions-1  |       "on_behalf_of": null,
nhost-api-functions-1  |       "payment_method": "pm_1NIiW8KE0B3nGMSOp2IMSUhf",
nhost-api-functions-1  |       "payment_method_options": {
nhost-api-functions-1  |         "card": {
nhost-api-functions-1  |           "installments": null,
nhost-api-functions-1  |           "mandate_options": null,
nhost-api-functions-1  |           "network": null,
nhost-api-functions-1  |           "request_three_d_secure": "automatic"
nhost-api-functions-1  |         },
nhost-api-functions-1  |         "cashapp": {
nhost-api-functions-1  |         },
nhost-api-functions-1  |         "link": {
nhost-api-functions-1  |           "persistent_token": null
nhost-api-functions-1  |         }
nhost-api-functions-1  |       },
nhost-api-functions-1  |       "payment_method_types": [
nhost-api-functions-1  |         "card",
nhost-api-functions-1  |         "link",
nhost-api-functions-1  |         "cashapp"
nhost-api-functions-1  |       ],
nhost-api-functions-1  |       "processing": null,
nhost-api-functions-1  |       "receipt_email": "redacted@gmail.com",
nhost-api-functions-1  |       "review": null,
nhost-api-functions-1  |       "setup_future_usage": null,
nhost-api-functions-1  |       "shipping": null,
nhost-api-functions-1  |       "source": null,
nhost-api-functions-1  |       "statement_descriptor": null,
nhost-api-functions-1  |       "statement_descriptor_suffix": null,
nhost-api-functions-1  |       "status": "succeeded",
nhost-api-functions-1  |       "transfer_data": null,
nhost-api-functions-1  |       "transfer_group": null
nhost-api-functions-1  |     }
nhost-api-functions-1  |   },
nhost-api-functions-1  |   "livemode": false,
nhost-api-functions-1  |   "pending_webhooks": 3,
nhost-api-functions-1  |   "request": {
nhost-api-functions-1  |     "id": "req_KsnPyKXE0DKsHu",
nhost-api-functions-1  |     "idempotency_key": "redacted"
nhost-api-functions-1  |   },
nhost-api-functions-1  |   "type": "payment_intent.succeeded"
nhost-api-functions-1  | }

This looks correctly formatted and is output across multiple lines. This is different than the output from the nhost cloud logs tab (obviously ids will be different for another request):

2023-07-08 08:18:20 | functions | {"log":"{\n \"id\": \"evt_3NRa5OKE0B3nGMSO0CFqJ2EW\",\n \"object\": \"event\",\n \"api_version\": \"2022-11-15\",\n \"created\": 1688818685,\n \"data\": {\n \"object\": {\n \"id\": \"pi_3NRa5OKE0B3nGMSO0RSvJ72Q\",\n \"object\": \"payment_intent\",\n \"amount\": 299,\n \"amount_capturable\": 0,\n \"amount_details\": {\n \"tip\": {\n }\n },\n \"amount_received\": 299,\n \"application\": null,\n \"application_fee_amount\": null,\n \"automatic_payment_methods\": {\n \"allow_redirects\": \"always\",\n \"enabled\": true\n },\n \"canceled_at\": null,\n \"cancellation_reason\": null,\n \"capture_method\": \"automatic\",\n \"client_secret\": \"pi_3NRa5OKE0B3nGMSO0RSvJ72Q_secret_nqCSEpOz7QQIJnvZ5pp2cauSQ\",\n \"confirmation_method\": \"automatic\",\n \"created\": 1688818682,\n \"currency\": \"usd\",\n \"customer\": \"cus_O5mktKeMXk9TjT\",\n \"description\": \"10 token(s)\",\n \"invoice\": null,\n \"last_payment_error\": null,\n \"latest_charge\": \"ch_3NRa5OKE0B3nGMSO0FZhYWu3\",\n \"livemode\": false,\n \"metadata\": {\n \"tokens\": \"10\",\n \"userId\": \"0291f8fc-9698-4792-89fb-cca9c04e1e84\"\n },\n \"next_action\": null,\n \"on_behalf_of\": null,\n \"payment_method\": \"pm_1NJbSAKE0B3nGMSOCNC0m6Xq\",\n \"payment_method_options\": {\n \"card\": {\n \"installments\": null,\n \"mandate_options\": null,\n \"network\": null,\n \"request_three_d_secure\": \"automatic\"\n },\n \"cashapp\": {\n },\n \"link\": {\n \"persistent_token\": null\n }\n },\n \"payment_method_types\": [\n \"card\",\n \"link\",\n \"cashapp\"\n ],\n \"processing\": null,\n \"receipt_email\": \"redacted@gmail.com\",\n \"review\": null,\n \"setup_future_usage\": null,\n \"shipping\": null,\n \"source\": null,\n \"statement_descriptor\": null,\n \"statement_descriptor_suffix\": null,\n \"status\": \"succeeded\",\n \"transfer_data\": null,\n \"transfer_group\": null\n }\n },\n \"livemode\": false,\n \"pending_webhooks\": 1,\n \"request\": {\n \"id\": \"req_zJXgP2ie9gn3X9\",\n \"idempotency_key\": \"redacted\"\n },\n \"type\": \"payment_intent.succeeded\"\n}","path":"/payment/stripe_hook","requestId":"9488c853-511f-41f8-b714-2279eaef4abe","level":"INFO"}
-- | -- | --
2023-07-08 08:18:20 | functions | {"log":"rawBody:","path":"/payment/stripe_hook","requestId":"9488c853-511f-41f8-b714-2279eaef4abe","level":"INFO"}

If I strip the \n and replace \" with just " the content are the same. So it seems that there is some processing happening. It's also not clear how much of that escaping is from the wrapper that puts the log data into the console or if it's also applying to the function.

@dbarrosop I'm not sure what else to verify, so let me know if you have any other suggestions!

@wollerman
Copy link
Contributor Author

I had an idea to validate the content can be parsed as json. Here's the local output:

nhost-api-functions-1  | bodyIsValidJson: false
nhost-api-functions-1  | rawBodyIsValidJson: true

And here's cloud output:

2023-07-08 08:49:24 | functions | {"log":"rawBodyIsValidJson: true","path":"/payment/stripe_hook","requestId":"e61a3175-44a3-4392-b17b-940b2460194b","level":"INFO"}
-- | -- | --
2023-07-08 08:49:24 | functions | {"log":"bodyIsValidJson: false","path":"/payment/stripe_hook","requestId":"e61a3175-44a3-4392-b17b-940b2460194b","level":"INFO"}

So formatting differences are definitely just from console and it should be valid.

That means the rawBody is fine and this is a red herring for stripe failure. The only other input to that validate function is the secret which I've pasted back in a few different times.

So I finally just logged my stripe secret (for the test mode), and now it's working?

Maybe I had some weird step where the secret was wrong, but I don't know what a good way to validate when it's set correctly because the nhost console doesn't show the value.

Closing this issue, but hopefully anyone running into this in the future will see this and triple check secret values.

@wollerman
Copy link
Contributor Author

Even though this is closed, I wonder @dbarrosop is there any way to verify that secret changes are picked up by just setting them in the console? Or does a full deploy need to be triggered?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants