CORS error only on PUT / POST with nginx proxy upstream server

384 views Asked by At

I added a traffic distributor (nginx) in front of my Jelastic server which was running without any issues before.

GET requests and login POST work fine, but once logged in, POST and PUT requests are failing with the known CORS error (these are for the actual request, preflights work fine):

Access to XMLHttpRequest at '' from origin 'xyz' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

and response headers are (error code is 500):

Content-Length:
383

Content-Type:
text/html
Date:
Thu, 20 Jul 2023 11:46:56 GMT
Etag:
"6194d09a-17f"
Server:
nginx

Same error is happening with Firefox, also tested on another machine running Linux.

The weird thing is it works from Safari browser. If I do the same POST / PUT request from there, I get these response headers:

:status: 201
Access-Control-Allow-Origin: *
Alt-Svc: h3=":443"; ma=86400
Content-Length: 956
Content-Security-Policy: default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests
Content-Type: application/json; charset=utf-8
Cross-Origin-Opener-Policy: same-origin
Date: Thu, 20 Jul 2023 11:12:56 GMT
ETag: W/"3bc-A0RyA0BcEO6RQG+lbMpZAiISc0Y"
origin-agent-cluster: ?1
Referrer-Policy: no-referrer
Server: nginx
Strict-Transport-Security: max-age=15552000; includeSubDomains
X-Content-Type-Options: nosniff
X-DNS-Prefetch-Control: off
x-download-options: noopen
X-Frame-Options: SAMEORIGIN
x-permitted-cross-domain-policies: none
X-XSS-Protection: 0

CURL request from Brave/Chrome:

curl 'https://dev-backend.xyz.app/api/collections/722/collectibles/4708' \
  -X 'PUT' \
  -H 'authority: dev-backend.xyz.app' \
  -H 'accept: application/json, text/plain, */*' \
  -H 'accept-language: en-GB,en;q=0.9' \
  -H 'authorization: Bearer abcdef' \
  -H 'content-type: application/json' \
  -H 'origin: https://dev.xyz.app' \
  -H 'referer: https://dev.xyz.app/' \
  -H 'sec-ch-ua: "Not.A/Brand";v="8", "Chromium";v="114", "Brave";v="114"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "macOS"' \
  -H 'sec-fetch-dest: empty' \
  -H 'sec-fetch-mode: cors' \
  -H 'sec-fetch-site: same-site' \
  -H 'sec-gpc: 1' \
  -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' \
  --data-raw '{jsondata}"

CURL request from Safari:

curl 'https://dev-backend.xyz.app/api/collections/722/collectibles/4708' \
-X 'PUT' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/plain, */*' \
-H 'Authorization: Bearer abcdef' \
-H 'Sec-Fetch-Site: same-site' \
-H 'Accept-Language: en-GB,en;q=0.9' \
-H 'Accept-Encoding: gzip, deflate, br' \
-H 'Sec-Fetch-Mode: cors' \
-H 'Host: dev-backend.xyz.app' \
-H 'Origin: https://dev.xyz.app' \
-H 'Content-Length: 944' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5.1 Safari/605.1.15' \
-H 'Referer: https://dev.xyz.app/' \
-H 'Connection: keep-alive' \
-H 'Sec-Fetch-Dest: empty' \
--data-binary '{jsondata}'

current NGINX config:

location / {
                        if ($request_method = 'OPTIONS') {
                           add_header 'Access-Control-Allow-Origin' $http_origin;
                            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
                            add_header 'Access-Control-Allow-Credentials' 'true';
                            add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,Accept';
                            add_header 'Access-Control-Max-Age' 86400;
                            return 204;
                        }
      
                        add_header 'Access-Control-Allow-Origin' $http_origin;
                        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
                        add_header 'Access-Control-Allow-Credentials' 'true';
                        add_header 'Access-Control-Allow-Headers' 'Range, Authorization, Content-Type, x-session-token';
                        add_header 'Access-Control-Max-Age' 3600;
                        

                        proxy_pass http://common;
                }

Any help with this is appreciated.

I tried various nginx config changes, nothing is working so far.

2

There are 2 answers

0
Akshat Jain On

Use 'always' in addition to * for access-control-allow-origin. Because sometimes maybe the Framework you are using is not handling the Pre-Flight request properly and not returning right response in that case this issue arises.

Check: https://nginx.org/en/docs/http/ngx_http_headers_module.html

To see how to use 'always'.

Don't forget to give me like if this helped you.

Example:

location / {
    add_header 'Access-Control-Allow-Origin' '*' always;
    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
    add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
    add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;

    if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Max-Age' 1728000 always;
        add_header 'Content-Type' 'text/plain; charset=utf-8' always;
        add_header 'Content-Length' 0 always;
        return 204;
    }

    # Your other Nginx configurations...
}
2
Kahdul On

I tried everything to resolve this and in the end I just needed to update my browser.