Cors not working with POST request with Docker and Nginx #543
Description
I am using Docker + Nginx to proxy requests between my frontend React project on localhost
to backend Laravel API on localhost:8080
.
I try to register a new user from the frontend on localhost/register
to Laravel localhost:8080/api/register
The GET
request to sanctum/csrf-cookie
works and it sets the XSRF-TOKEN
But then I try to send POST
request to register a user and I get CORS error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at http://localhost:8080/api/register. (Reason:
CORS header ‘Access-Control-Allow-Origin’ is missing)
And despite this message, the user is registered successfully. But the error still appears because indeed the response does not contain the ‘Access-Control-Allow-Origin’ header.
I'm not sure if something in the middle (nginx, docker) is blocking it, but the GET
request clearly works because when I try to change the allowed_origins
in my cors.php
file it throws an error.
This is my cors.php
:
'paths' => ['api/*', 'sanctum/csrf-cookie'],
'allowed_methods' => ['*'],
'allowed_origins' => ['http://localhost'],
'allowed_origins_patterns' => ['*'],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
This is the OPTIONS
response headers:
Status 204 No Content
Version HTTP/1.1
Transferred 494 B (0 B size)
Referrer Policy strict-origin-when-cross-origin
HTTP/1.1 204 No Content
Server: nginx/1.20.1
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
X-Powered-By: PHP/8.0.10
Cache-Control: no-cache, private
Date: Fri, 10 Sep 2021 11:03:28 GMT
Access-Control-Allow-Origin: http://localhost
Vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: content-type,x-xsrf-token
Access-Control-Max-Age: 0
This is the OPTIONS
request headers:
Status 204 No Content
Version HTTP/1.1
Transferred 494 B (0 B size)
Referrer Policy strict-origin-when-cross-origin
Access-Control-Allow-Credentials
true
Access-Control-Allow-Headers
content-type,x-xsrf-token
Access-Control-Allow-Methods
POST
Access-Control-Allow-Origin
http://localhost
Access-Control-Max-Age
0
Cache-Control
no-cache, private
Connection
keep-alive
Content-Type
text/html; charset=UTF-8
Date
Fri, 10 Sep 2021 11:07:14 GMT
Server
nginx/1.20.1
Vary
Origin, Access-Control-Request-Method, Access-Control-Request-Headers
X-Powered-By
PHP/8.0.10
OPTIONS /api/register HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type,x-xsrf-token
Referer: http://localhost/
Origin: http://localhost
Connection: keep-alive
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
This is the POST
response headers:
Status 200 OK
Version HTTP/1.1
Transferred 16.68 KB (16.49 KB size)
Referrer Policy strict-origin-when-cross-origin
HTTP/1.1 200 OK
Server: nginx/1.20.1
Date: Fri, 10 Sep 2021 11:09:32 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/8.0.10
Accept
application/json
Accept-Encoding
gzip, deflate
Accept-Language
en-US,en;q=0.5
Connection
keep-alive
Content-Length
62
Content-Type
application/json
Cookie
XSRF-TOKEN=long-value-here
Host
localhost:8080
Origin
http://localhost
Referer
http://localhost/
Sec-Fetch-Dest
empty
Sec-Fetch-Mode
cors
Sec-Fetch-Site
cross-site
User-Agent
Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0
X-XSRF-TOKEN long-value-here
This is the POST
request headers:
Status 200 OK
Version HTTP/1.1
Transferred 16.68 KB (16.49 KB size)
Referrer Policy strict-origin-when-cross-origin
HTTP/1.1 200 OK
Server: nginx/1.20.1
Date: Fri, 10 Sep 2021 11:09:32 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/8.0.10
POST /api/register HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json
X-XSRF-TOKEN: long-value-here
Content-Length: 62
Origin: http://localhost
Connection: keep-alive
Referer: http://localhost/
Cookie: XSRF-TOKEN=long-value-here
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
In order to fix this CORS error I added the following to my nginx config:
set $METHODS 'GET, POST, OPTIONS, HEAD';
set $HEADERS 'Authorization, Origin, X-Requested-With, Content-Type, Accept';
if ( $request_method = POST ){
add_header 'Access-Control-Allow-Origin' 'http://localhost';
add_header 'Access-Control-Allow-Credentials' 'true';
}
}
So now my nginx config file looks like this:
server {
listen 8080;
index index.php index.html;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/html/public;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri = 404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
set $METHODS 'GET, POST, OPTIONS, HEAD';
set $HEADERS 'Authorization, Origin, X-Requested-With, Content-Type, Accept';
if ( $request_method = POST ){
add_header 'Access-Control-Allow-Origin' 'http://localhost';
add_header 'Access-Control-Allow-Credentials' 'true';
}
}
}
server {
listen 80;
location / {
proxy_pass http://node:3000;
}
}
So manually telling nginx to send back these headers for the POST
request work, but why I don't get this issue for GET
and OPTIONS
?