skip to Main Content
[edited on 20230428 adding info about nginx]

I’m setting up Stripe in a React/Node project. To support the payment workflow, the server must listen for two types of POST requests:

  1. /create-payment-intent. This request comes from the browser. I got that working without problem.

  2. /webhook. These requests come from the Stripe server, and I cannot get it working. My server responds with http error 401, but I have no idea why.

A bit more context about my development environment: I develop on code-server, remotely. This means that when I debug, incoming request have two reverse proxies to pass by:

  1. nginx forwarding requests for https://<my-code-server-domain> to code-server running on localhost:8082

  2. code-server forwarding request for https://<my-code-server-domain>/proxy/3024/* to the node app running on localhost:3024

E.g.:

https://<my-code-server-domain>/proxy/3024/create-payment-intent

and

https://<my-code-server-domain>/proxy/3024/webhook

This is how the POST request handler is defined on the server:

const app = express()
app.post("/webhook",  express.raw({type: 'application/json'}), async (req, res) => {
    let event = req.body;
    ...

Breakpoints show that the request handler isn’t executed at all, so the request must be returned before express calls the handler.

Suspecting a cors issue, because receiving browser POST requests works, but receiving non-browser POST requests fails, I’ve tried adding the ‘cors’ NPM module and also tried setting more liberate cors headers manually, but I kept getting error 401.

For testing Stripe webhook events, there’s an executable that connects to the Stripe server and forwards the events to any URL that you specify. I’ve tried running this executable on my code-server development server itself and also on another PC, which didn’t make any difference.

I’m not sure how to proceed from here… where should I be looking to debug this problem? Can it be a problem with the setup of the code-server reverse proxy? Can it even be something at OS level?

In nginx access.log, I can see how requests for /proxy/3024/create-payment-intent are answered with 200 and requests for /proxy/3024/webhook are answered with 401:

134.54.10.136 - - [28/Apr/2023:06:53:52 +0000] "POST /proxy/3024/create-payment-intent HTTP/1.1" 200 79 "https://nerd.gelovenleren.net/proxy/3022/edit/en/834a980b-ad65-4734-94ec-e1153f901a90/?payment_intent=pi_3N1kt9CPmkmZOx8V1AHUoWRa&payment_intent=pi_3N1kxmCPmkmZOx8V1GoNP6Fp&payment_intent_client_secret=...payment_intent_client_secret=...&redirect_status=succeeded&redirect_status=succeeded" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0"
37.97.145.69 - - [28/Apr/2023:06:53:53 +0000] "POST /proxy/3024/webhook HTTP/1.1" 401 24 "-" "Stripe/1.0 (+https://stripe.com/docs/webhooks)"

In nginx error.log, I find this passage, where it’s processing the webhook request, and where "401 Unauthorized" is mentioned, but I can’t interprete it. Is this something nginx is generating on its own, or is it something it gets back as a result of forwarding the request to code-server??

2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http run request: "/proxy/3024/webhook?"
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http upstream check client, write event:0, "/proxy/3024/webhook"
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http upstream request: "/proxy/3024/webhook?"
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http upstream process header
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 malloc: 000055DBE9E2AFA0:4096
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 recv: eof:0, avail:-1
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 recv: fd:29 241 of 4096
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http proxy status 401 "401 Unauthorized"
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http proxy header: "Content-Type: application/json; charset=utf-8"
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http proxy header: "Content-Length: 24"
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http proxy header: "ETag: W/"18-XPDV80vbMk4yY1/PADG4jYM4rSI""
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http proxy header: "Vary: Accept-Encoding"
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http proxy header: "Date: Fri, 28 Apr 2023 06:53:52 GMT"
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http proxy header: "Connection: close"
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http proxy header done
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 xslt filter header
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 HTTP/1.1 401 Unauthorized
Server: nginx/1.18.0 (Ubuntu)
Date: Fri, 28 Apr 2023 06:53:52 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 24
Connection: keep-alive
ETag: W/"18-XPDV80vbMk4yY1/PADG4jYM4rSI"
Vary: Accept-Encoding

2023/04/28 06:53:52 [debug] 2331377#2331377: *18 write new buf t:1 f:0 000055DBE9E30B50, pos 000055DBE9E30B50, size: 253 file: 0, size: 0
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http write filter: l:0 f:0 s:253
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http cacheable: 0
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http proxy filter init s:401 h:0 c:0 l:24
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http upstream process upstream
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 pipe read upstream: 0
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 pipe preread: 24
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 pipe buf free s:0 t:1 f:0 000055DBE9E2AFA0, pos 000055DBE9E2B079, size: 24 file: 0, size: 0
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 pipe length: 24
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 input buf #0
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 pipe write downstream: 1
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 pipe write downstream flush in
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http output filter "/proxy/3024/webhook?"
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http copy filter: "/proxy/3024/webhook?"
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 image filter
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 xslt filter body
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http postpone filter "/proxy/3024/webhook?" 000055DBE9E2FF68
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 write old buf t:1 f:0 000055DBE9E30B50, pos 000055DBE9E30B50, size: 253 file: 0, size: 0
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 write new buf t:1 f:0 000055DBE9E2AFA0, pos 000055DBE9E2B079, size: 24 file: 0, size: 0
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http write filter: l:0 f:0 s:277
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http copy filter: 0 "/proxy/3024/webhook?"
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 pipe write downstream done
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 event timer: 29, old: 585225784, new: 585225788
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 http upstream exit: 0000000000000000
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 finalize http upstream request: 0
2023/04/28 06:53:52 [debug] 2331377#2331377: *18 finalize http proxy request

Best regards,
Vic

2

Answers


  1. Chosen as BEST ANSWER

    Code server is requiring authentication also when doing port forwarding. So it's by design. See more info in my issue on GitHub; https://github.com/coder/code-server/issues/6174#issuecomment-1530072355

    Nginx had nothing to do with it, it was just forwarding the 401 error that it got from code server.

    Workaround is to use the exposed port on localhost directly. This only works when making requests from the machine where code server is running!


  2. Based on this page, here’s what a 401 error is:

    [It] indicates that the client request has not been completed because it lacks valid authentication credentials for the requested resource.

    So it looks like Stripe tried to send you an event, but you server didn’t allow Stripe’s request and returned a 401.

    To fix this, you need to make sure your webhook endpoint URL is publicly accessible, as mentioned here. And if needed, whitelist Stripe IP addresses.

    One way to debug this is to try sending an empty POST request to your endpoint, and make sure your server doesn’t respond with a 401 error. curl -X POST https://xxx/webhook

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search