Axios send wrong cookies (CORS) - http

I am using local development server (on my computer) for frontend. Backend is located on another server and I sending requests from frontend to backend using CORS.
It works ok, but when I passing cookies from frontend, It passed incorrect: namely the csrf token is different from what is stored in cookies.
Examples:
Cookies on Chrome dev tools, Application tab: csrf_token: b2o3q06llj
Request headers:
As you can see, header Cookie is different from data viewed on Application tab. X-Csrf-Token is correct, but Cookie header is wrong. It must contain csrf_token which is available on Dev tools > Application > Storage > Cookies
CORS setup in Nginx config (remote server):
if ($request_method ~* "(GET|POST)") {
add_header 'Access-Control-Allow-Origin' 'http://192.168.1.127:3000' always;
add_header 'Access-Control-Allow-Credentials' 'true' 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, X-Csrf-Token, Cache-Control' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
}
# Preflighted requests
if ($request_method = OPTIONS ) {
add_header "Access-Control-Allow-Origin" 'http://192.168.1.127:3000' always;
add_header "Access-Control-Allow-Credentials" 'true' always;
add_header "Access-Control-Allow-Methods" "GET, POST, OPTIONS, HEAD" always;
add_header "Access-Control-Allow-Headers" "Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Csrf-Token, Cache-Control" always;
return 204;
}
Axios setup:
axios.create({
baseURL: window.location.protocol + '//' +window.location.hostname + (window.location.port ? ':' + window.location.port : '') + '/data',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Csrf-Token': <token>,
'X-Requested-With': 'XMLHttpRequest'
},
withCredentials: true
});
I can not understand what the problem is. Why does axios not send correct cookies?

Related

Set response headers for nginx post requests

Nginx post requests seem to be removing my headers, so how can I get the header "Access-Control-Allow-Origin" to stay on post requests?
location /api {
proxy_pass http://127.0.0.1:3567/;
if ($request_method = OPTIONS) {
add_header "Access-Control-Allow-Origin" "http://localhost:8080";
add_header "Access-Control-Allow-Methods" "GET, POST, OPTIONS";
add_header "Content-Type" "text/plain";
add_header "Access-Control-Allow-Credentials" "true";
add_header "Access-Control-Allow-Headers" "content-type,rid,fdi-version";
add_header "Content-Length" 0;
return 204;
}
add_header "Access-Control-Allow-Origin" "http://localhost:8080";
}
Right now, it works when the request method is set to OPTIONS but not for POST requests. I would expect there to be the header "Access-Control-Allow-Origin" on my response, but there is not
Is your POST request returning an error response by any chance? If so change
add_header "Access-Control-Allow-Origin" "http://localhost:8080";
to
add_header "Access-Control-Allow-Origin" "http://localhost:8080" always;

Nginx uinit cors

I want to handle cors on nginx unit level but I don't know how it make on nginx unit.
Example config for nginx
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, OPTIONS, DELETE, PATCH';
add_header 'Access-Control-Allow-Headers' 'Authorization,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range';
add_header 'Access-Control-Expose-Headers' 'Gc-Export-Errors';
return 204;
}
How I can do this for nginx unit?
Currently, Nginx Unit doesn't support functionality equal to add_header so if you need custom headers for 204 response it should be done using application. And configuration will looks like this:
{
"match":{
"method": "OPTIONS"
},
"action":{
"proxy": "path/to/app_return_204_with_custom_headers"
}
}

Nginx Cors with POST

I'm trying to send a post request from a client-side javascript (fetch) to my server which uses Nginx as the web server. The client-side javascript runs on a different domain.
I'm having trouble configuring Nginx to reply with the proper headers, when I try the config below, I get a 405 Not Allowed on the preflight request:
location /cookie/ {
root /myPlace;
add_header Allow 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Origin' '$http_origin' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
index index.php;
}
When I try the configuration below, the preflight is successful and it contains all the headers needed for CORS, but the main request errors to MissingAllowOriginHeader the console error is the familiar No 'Access-Control-Allow-Origin' header is present on the requested resource.
Here is the config which results in the behavior described above:
location /cookie/ {
root /myPlace;
add_header Allow 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Origin' '$http_origin' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
add_header 'Access-Control-Allow-Origin' '$http_origin' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-headers' 'Content-Type' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
return 204;
}
index index.php;
}
The strange thing is that the main request in this case doesn't return any CORS headers, although the preflight has all the necessary headers and doesn't error out.
Any idea how can I get past these CORS errors
If it helps, this is the javascript code I use on the client-side:
let theData = {
id: "123",
};
fetch("https://myServer.com/cookie/", {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
headers: {
'Content-Type': 'application/json'
},
redirect: 'follow',
body: JSON.stringify(theData),
});
Thank you

django-cors-headers and nginx config: preflight response missing CORS headers

I use django-cors-headers 3.1.1 for handling the requests and responses between my Django-backend and Javascript-frontend apps. Transport is non-secured (i.e. http, not https).
When hosted locally, everything works fine. But after deploying on the server, I stopped seeing the CORS headers.
Here are headers in development:
and in production:
Error message:
Access to XMLHttpRequest at 'http://[HOST_IP]/api/assets/' from origin 'http://my_custom_domain.eu' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
My nginx configurations looks as follows:
server {
listen 80;
server_name [HOST_IP];
location / {
include proxy_params;
proxy_pass http://unix:/home/ubuntu/[path_to_app]/app.sock;
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Max-Age' 86400;
if ($request_method = 'OPTIONS') {
add_header 'Content-Type' 'text/html; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'PUT') {
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
}
location /static/ {
autoindex on;
alias /home/ubuntu/[path_to_app]/site/static/;
}
}
The django-cors-headers’ settings are now identical in development and in production:
INSTALLED_APPS = (
…
"corsheaders",
…
)
MIDDLEWARE = [
…
"corsheaders.middleware.CorsMiddleware",
"django.middleware.common.CommonMiddleware",
…
]
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_METHODS = ['DELETE','GET','OPTIONS','PATCH','POST','PUT']
On the client side I tried to add ‘'Access-Control-Request-Method’: ‘PUT’ header, but this was refused by the browser. There’s noting unusual in the client call:
axios({
method: 'put',
url: `${this.backendUrl}/api/assets/`,
data: formData,
headers: {
'Content-Type': 'application/octet-stream',
}
})
Also, I’m trying to host on the Amazon AWS EC2 for the first time, so perhaps there is some required AWS configuration I am not aware of. For example, is it necessary to enable CORS using the API Gateway? The documentation does not say so (‘If you are using the API Gateway Import API, you can set up CORS support using an OpenAPI file’).
The frontend application is hosted on a S3 bucket with the following CORS policy:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>GET</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
What am I missing here? Is there some needed server-side (nginx especially) configuration?
Some other solutions I’ve tried:
I have doubts, whether the request/response origin is correct (e.g. APPEND_SLASH variable). But if this is the case, shouldn’t an error be raised when hosted locally?
I also tried setting proxy headers as in this question, but without knowing nginx very well this was doomed to fail.
I managed to solve this issue by changing 3 things:
AWS
I noticed that AWS documentation states:
CORS is already enabled for the Amazon EC2 API, and is ready for you
to use. You do not need to perform any additional configuration steps
to start using this feature. There is no change to the way that you
make calls to the Amazon EC2 API; they must still be signed with valid
AWS credentials to ensure that AWS can authenticate the requestor. […]
This is usually handled by AWS SDK or CLI, but in my case I used none of them, so I had to add AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. In my case I simply used aws4 library:
axios(aws4.sign({
accessKeyId: this.awsAccessKey,
secretAccessKey: this.awsSecretAccessKey,
method: 'put',
url: `${this.backendUrl}/api/assets/`,
data: formData,
body: JSON.stringify(formData),
service: 'ec2',
region: 'eu-central-1',
path: '/',
headers: {
'Content-Type': 'application/octet-stream'
}
}))
I’ve seen plenty of examples how to add AWS Signature v.4 without any additional dependency, though.
NGINX
In nginx configuration I placed all add_headers statements into conditional code-blocks. Idea came from this post.
server {
listen 80;
server_name [HOST_IP];
location / {
include proxy_params;
proxy_pass http://unix:/home/ubuntu/[path_to_app]/app.sock;
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS, POST, DELETE';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Amz-Date';
add_header 'Access-Control-Max-Age' 86400;
add_header 'Content-Type' 'text/html; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'PUT') {
add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS, POST, DELETE';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Amz-Date';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, PUT, OPTIONS, POST, DELETE';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,X-Amz-Date';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
}
location /static/ {
autoindex on;
alias /home/ubuntu/analizy/be/site/static/;
}
}
Django-cors-header
Here it sufficed to add non-default headers.
from corsheaders.defaults import default_headers
CORS_ALLOW_HEADERS = list(default_headers) + [
'X-Amz-Date',
]
Hope that this will help someone.

Enabling CORS on nginx

I have followed this example to enable CORS on my API subdomain so that I can send requests to it from SwaggerUI. This is the output I get from running OPTIONS on that subdomain:
curl -i -X OPTIONS http://api.MYDOMAIN.com/v1/data/extraction
HTTP/1.1 204 No Content
Server: nginx/1.10.3 (Ubuntu)
Date: Wed, 18 Apr 2018 20:45:52 GMT
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-API-Key
Access-Control-Max-Age: 1728000
Content-Type: text/plain charset=UTF-8
Content-Length: 0
I'm stuck on where to go to figure out why in Chrome on my docs subdomain (same DOMAIN.com server) it still gives me this. Can anyone advise where I should look to?
I had a similar issue and couldn't get it to work. This setup finally worked for me. https://gist.github.com/Stanback/7145487 this is what it looks like. I just set $cors 'true' to test if it worked. It worked for me. This is all in the /location {...} area
set $cors '';
if ($http_origin ~ '^https?://(localhost|www\.yourdomain\.com|www\.yourotherdomain\.com)') {
set $cors 'true';
}
if ($cors = 'true') {
add_header 'Access-Control-Allow-Origin' "$http_origin" always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;
# required to be able to read Authorization header in frontend
#add_header 'Access-Control-Expose-Headers' 'Authorization' always;
}
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' "$http_origin" always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;
# required to be able to read Authorization header in frontend
#add_header 'Access-Control-Expose-Headers' 'Authorization' always;
# Tell client that this pre-flight info is valid for 20 days
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
All it came down to the fact that NGINX had used more_set_headers instead of add_header (it may've been that NGINX had this module enabled) and after that using one of the above examples with it made it working.
You might want to test a call to api.MYDOMAIN.com/v1/data/extraction with curl and a CORS origin header.
curl -i -X POST -H "Origin: http://docs.whatever.com" \
--verbose http://api.MYDOMAIN.com/v1/data/extraction
The response should come back with the header:
Access-Control-Allow-Origin: *
If that header does not come back with the response, chrome will throw an error like what you saw.
P.S. there is a mention in the error that nginx responded with a 404, which might have something to do with it.
The problem might well be that Access-Control-Allow-Origin: * and Access-Control-Allow-Credentials: true are incompatible - if you want to pass credentials, you will need to respond with Access-Control-Allow-Origin: {value-of-Origin-request-header} and Access-Control-Allow-Credentials: true.

Resources