This is different from other cors related questions
I am running my node backend-api on microservices on kubernetes deployed on Digitalocean. I have literally read all the blogs/forums related to this issue and haven't found any solution (specifically the ones related to Digitalocean).
I am unable to connect to the cluster via React application running on 'localhost:3000' or anywhere outside the kubernetes cluster.
It is giving me below error:
Access to XMLHttpRequest at 'http://cultor.dev/api/users/signin'
from origin 'http://localhost:3000' has been blocked by
CORS policy: Response to preflight request doesn't pass access
control check: Redirect is not allowed for a preflight request.
The kubernetes cluster's loadbalancer is listening on "cultor.dev" which is set as a local domain in /etc/hosts.
I am able to make it work using Postman!
NOTE:
I have tried using cors package as well, it won't help. Also, it works fine if I run this react app inside of the kubernetes cluster which I do not want.
Ingress nginx config (tried using annotations mentioned on the official website):
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-service
## this tells ingress to pick up the routing rules mentioned in this config
annotations:
nginx.ingress.kubernetes.io/default-backend: ingress-nginx-controller
kubernetes.io/ingress.class: nginx
## tells ingress to check for regex in the config file
nginx.ingress.kubernetes.io/use-regex: 'true'
# nginx.ingress.kubernetes.io/enable-cors: 'true'
# nginx.ingress.kubernetes.io/cors-allow-methods: "PUT, GET, POST, OPTIONS"
# nginx.ingress.kubernetes.io/cors-allow-origin: "*"
# nginx.ingress.kubernetes.io/cors-max-age: 600
# certmanager.k8s.io/cluster-issuer: letsencrypt
# kubernetes.io/ingress.class: nginx
# service.beta.kubernetes.io/do-loadbalancer-enable-proxy-protocol: "true"
One of the microservices config (tried cors package as well):
// APP SETTINGS
app.set('trust proxy', true);
app.use(json());
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', '*');
res.header('Access-Control-Request-Headers', '*');
if (req.method === "OPTIONS") {
res.header('Access-Control-Allow-Methods', '*');
return res.status(200).json({});
}
next();
});
Okay, after alot of research and with the help of the other answers I did the following:
I changed the request to the backend (from the client side) to https instead of http. This fixed the error Redirect is not allowed for a preflight request
I changed the config ingress nginx config to get rid of the error multiple values in Access-Control-Allow-Origin :
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-service
annotations:
nginx.ingress.kubernetes.io/default-backend: ingress-nginx-controller
kubernetes.io/ingress.class: nginx
## tells ingress to check for regex in the config file
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/configuration-snippet: |
add_header Access-Control-Allow-Methods "POST, GET, OPTIONS";
add_header Access-Control-Allow-Credentials true;
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-methods: "PUT, GET, POST, OPTIONS"
I hope it helps others as well.
Why are the cors settings commented?
nginx.ingress.kubernetes.io/configuration-snippet: |
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Methods "POST, GET, OPTIONS";
add_header Access-Control-Allow-Credentials true;
Same issue on GitHub
Redirect is not allowed for a preflight request.
Seems like there is a redirect happening. There isn't enough information to conclude where. My guess is that you have TLS set up on your Ingress and http://cultor.dev/api/users/signin is being automatically redirected to https.
CORS policy: Response to preflight request doesn't pass access
control check: Redirect is not allowed for a preflight request.
The preflight CORS request is actually a separate request that the browser makes to your server to check if the access control headers sent back in the response will accept the main request. The preflight request uses the HTTP OPTIONS method. I bet if you log the req.method for incoming requests you will see the OPTIONS requests coming in.
When you receive one of these preflight requests you should respond with the appropriate Access-Control-Allow-Origin and Access-Control-Allow-Headers response headers.
Related
I have a website, https://example.com which upon load, is supposed to fetch data from another website, https://subdomain.example.com:8080, but apparently, my requests are being blocked. Attached is what I see in the network tab in my browser. The request goes from the browser side to a proxy to the subdomain.example.com. What CORS headers do I need? I'm unfamiliar w/ CORS and I've tried reading the documentation & examples online to no avail.
https://example.com is blocked since it is not allowed at https://subdomain.example.com:8080.
Whoever is owning https://subdomain.example.com:8080 ,he has to add https://example.com in allowed server origin.
https://example.com and https://subdomain.example.com:8080 both are treated different when it comes to CORS.
For example, in nodejs express code, this is how CORS is added and the origin server is allowed.
here in my example http://localhost:8080 will be replaced by https://example.com
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:8080");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
complete code-
const bodyParser = require('body-parser')
const path = require('path');
const express = require('express');
const app = express();
const modelRoute = require('./model');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json())
app.use(express.static('dist'));
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:8080");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.get('/api/getData', modelRoute.getData);
app.post('/api/postData', modelRoute.postData);
app.listen(process.env.PORT || 8080, () => console.log(`Listening on port ${process.env.PORT || 8080}!`));
There could be two level of CORS enabled one at Nginx side and another on https://subdomain.example.com.
First you need to add below headers in nginx.conf at global level or a local server section.
nginx.conf may already have this header then you need add this as well.
add_header Access-Control-Allow-Origin https://example.com;
More importantly, first, you need to see what and how nginx.conf is configured. Based on that you can add this header in /location section as well if CORS is enabled location wise in nginx.conf.
this is one sample
# local node.js server
upstream websocket {
server 127.0.0.1:3000;
}
server {
server_name ...;
# ...;
# add the header here
add_header Access-Control-Allow-Origin https://example.com;
location /path/ {
proxy_hide_header 'Access-Control-Allow-Origin';
}
}
the request may get block due to other headers as well at nginx side. If above doen not work. You need to see what extra headers nginx.conf have. For exm -
add_header 'Access-Control-Allow-Origin' 'http://api.localhost';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH';
It would be easy to configure but may require some time to experiment.
You may look into below thread as well. It may help you to understand more.
NGINX Reverse Proxy and Access-Control-Allow-Origin issue
How to enable CORS in Nginx proxy server?
If nginx.conf looks good and still, it does not work then only you jump to subdomain website configuration. It will save your time.
I'm running a NodeJS App on NGINX Web Server. I'm able to access all the URLs in my app via iframe on other websites.
Here is my NGINX conf:
proxy_hide_header X-Frame-Options;
How do I restrict the iframe to allow only 1 URL instead of all the URLs?
Also, how do I allow only a few domains to access via iframe?
Can it be done via NGINX or should it be handled via NodeJS code?
It can be done via both NGINX conf and nodejs.
For NGINX conf, please use both X-Frame-Options and Content Security Policy (frame-ancestors)
add_header Content-Security-Policy "frame-ancestors domain1 domain2 domain3"; -> it's for modern browsers
add_header X-Frame-Options "ALLOW-FROM domain1 domain2 domain3"; -> it's for older browsers
To get more details: X-Frame-Options Content-Security-Policy
It can be done by both nginx or nodejs. If you'd prefer nginx, you should use it within a location block like:
server {
location / {
add_header Content-Security-Policy "frame-ancestors 'none'";
add_header X-Frame-Options "DENY";
}
location /iframing_is_allowed {
add_header Content-Security-Policy "frame-ancestors http: https:";
proxy_hide_header X-Frame-Options;
}
}
Otherwise, if you'd prefer nodejs, you should set these headers from your JS code in the corresponding endpoints.
If you looking for what options you have, please consult to X-Frame-Options and Content-Security-Policy docs, as Thang Duc pointed.
I used this in
Ubuntu 14.04
add_header X-Frame-Options "allow-from https://*.sample.com http://*.sample.com";
add_header Content-Security-Policy "frame-ancestors https://*.sample.com http://*.sample.com";
And it worked like a charm.
I am using W3 Total Cache with Amazon cloudfront. I have in my htaccess file:
# BEGIN W3TC CDN
<FilesMatch "\.(ttf|ttc|otf|eot|woff|font.css)$">
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>
</FilesMatch>
# END W3TC CDN
But still getting error:
Font from origin 'https://example.cloudfront.net' has been blocked from loading by Cross-Origin Resource Sharing policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://www.example.com' is therefore not allowed access.
Why is this happening?
Found the solution in this link: https://www.naschenweng.info/2014/09/23/wordpress-w3-total-cache-cloudfront-font-cors-issue/.
You need to change the CloudFront distribution's behaviors settings:
Change “Forward Headers” from “None” to “Whitelist”
Add “Origin” to the “Whitelist Headers”
Make sure that “Use Origin Cache Headers” is checked
Then invalidate the cached fonts.
Wrestling with this for days, and think I finally fixed it. Here are some things to check:
The webserver config should add the proper header. Apache syntax is listed in the question. Here's Nginx syntax that I used:
location ~* \.(eot|ttf|woff|woff2)$ {
add_header Access-Control-Allow-Origin '*';
}
Within W3TC > Performance > CDN > Custom File List, I added the following to upload the actual font files:
{plugins_dir}/*.ttf
{plugins_dir}/*.woff
While you're there, set the Theme file types to upload to the following. Per #Yao's link, the default separators are inconsistent (should all be semicolons, not commas)
*.css;*.js;*.gif;*.png;*.jpg;*.ico;*.ttf;*.otf;*.woff;*.less
In S3 > Permissions > CORS Configuration, change the default
<AllowedHeader>Authorization</AllowedHeader>
to:
<AllowedHeader>*</AllowedHeader>
You should start seeing the necessary Access-Control-Allow-Origin header in the response.
In CloudFront > Distribution > Behaviors, make the following changes:
Change Allowed HTTP Methods to GET, HEAD, OPTIONS (you need OPTIONS)
Change Forward Headers to Whitelist
Under Whitelist Headers, Add >> Origin
To test:
curl -I -s -X GET -H "Origin: www.example.com" https://abcdefg543210.cloudfront.net/wp-content/path/to/foo.ttf
This should give you back the following header:
Access-Control-Allow-Origin: *
X-Cache: Miss from cloudfront
I found this blog post to be pretty helpful:
http://blog.celingest.com/en/2014/10/02/tutorial-using-cors-with-cloudfront-and-s3/
basicly It's because the font isn't set to be shared outside of the domain that you are on, so you can just use it as a resourse for, in this case, https://example.cloudfront.net
This can be changed in the webserver settings though.
The problem may not always be with the origin settings on Nginx or Apache at your web server end.
You will also need to enable CORS on your S3 AWS account for this to work correctly.
I'm writing a web application using MEAN Stack and I've encountered a problem that I cannot solve, no matter what I try or search.
I'm trying to login using passport/passport-facebook with ExpressJS. If I write in the URL of my browser localhost/api/auth/facebook everything runs fine.
However if I create an element in my HTML code like this Login with Facebook it takes me to my 404 page (see nginx below).
And if I try with the Angular way, like this <button ng-click="login_fb()">Login with Facebook</button>, I get a No 'Access-Control-Allow-Origin' header is present on the requested resource. error.
I believe that I should use the <a href="..."> element but I think my nginx script is blocking it, since I enabled CORS on my NodeJS Server, with this:
server.all('/*', function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header("Access-Control-Allow-Headers", "X-Requested-With, Content-Type");
next();
});
I'll leave my nginx script too (ignore the blocks inside '<' and '>'):
worker_processes 4;
events {
worker_connections 1024;
}
http {
upstream backend {
server 127.0.0.1:8080;
}
# To optimize the response of static files
sendfile on;
server {
# Listen to normal port
listen 80;
# Let through files like CSS, JPG, JS, ...
include mime.types;
# Alias for this server
server_name <my-domain>;
# Where the HTML files are located
root <my-folder>;
# Route for API calls
location /api/ {
proxy_pass http://backend;
}
# Route for the index
location ~ ^/*$ {
index index.html index.htm;
}
# Route for 404 page
error_page 404 /index.html;
}
}
EDIT: Using the link like this Login with Facebook but it forces me to use the URL hardcoded and I'll eventually put this app under a domain.
NEW EDIT: I realise that using like this Login with Facebook doesn't work because it thinks it a Angular route, and since I haven't declared in $routeProvider, it takes me to 404.
To avoid the 404, add target="_self" to your link Login with Facebook. It will bypass the angular router.
With the other method, I think you get No 'Access-Control-Allow-Origin' because when you use the angular $http service it's blocked by CORS same-origin policy at the FB API.
You should stick to the link, if you want to do this on the angular end, I recommend this plugin: https://github.com/sahat/satellizer.
I can't figure out why my .htaccess header settings doesn't work.
My .htaccess file content:
Header set Access-Control-Allow-Origin *
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
Header always set Access-Control-Allow-Headers "*"
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [QSA,L]
But when I remove Header's and add them in index.php then everything works fine.
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: *");
What am i missing?
This should work:
Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "origin, x-requested-with, content-type"
Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
Just for the record, I was running into the exact same problem and none of the answers worked.
I used a headers checker tool: http://www.webconfs.com/http-header-check.php
I was testing with my IP (http://192.0.2.1/upload) and what came back was the following:
HTTP/1.1 301 Moved Permanently =>
Date => Sat, 10 Jan 2015 04:03:35 GMT
Server => Apache/2.2.21 (Win32) mod_ssl/2.2.21 OpenSSL/1.0.0e PHP/5.3.8 mod_perl/2.0.4 Perl/v5.10.1
Location => http://192.0.2.1/upload/
Content-Length => 380
Connection => close
Content-Type => text/html; charset=iso-8859-1
There was a redirection happening and the AJAX request does not honor/follow redirects.
It turned out to be the missing slash at the end of the domain (http://192.0.2.1/upload/)
I tested again with slash at the end and I got this below. Added a slash in the script too, and it was now working.
HTTP/1.1 200 OK =>
Date => Sat, 10 Jan 2015 04:03:53 GMT
Server => Apache/2.2.21 (Win32) mod_ssl/2.2.21 OpenSSL/1.0.0e PHP/5.3.8 mod_perl/2.0.4 Perl/v5.10.1
X-Powered-By => PHP/5.3.8
Access-Control-Allow-Origin => *
Access-Control-Allow-Methods => PUT, GET, POST, DELETE, OPTIONS
Access-Control-Allow-Headers => *
Content-Length => 1435
Connection => close
Content-Type => text/html
Use this tool to test if your headers are good and to troubleshoot what is happening.
I have a shared hosting on GoDaddy. I needed an answer to this question, too, and after searching around I found that it is possible.
I wrote an .htaccess file, put it in the same folder as my action page. Here are the contents of the .htaccess file:
Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "origin, x-requested-with, content-type"
Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
Here is my ajax call:
$.ajax({
url: 'http://www.mydomain.com/myactionpagefolder/gbactionpage.php', //server script to process data
type: 'POST',
xhr: function() { // custom xhr
myXhr = $.ajaxSettings.xhr();
if(myXhr.upload){ // check if upload property exists
myXhr.upload.addEventListener('progress',progressHandlingFunction, false); // for handling the progress of the upload
}
return myXhr;
},
//Ajax events
beforeSend: beforeSendHandler,
success: completeHandler,
error: errorHandler,
// Form data
data: formData,
//Options to tell JQuery not to process data or worry about content-type
cache: false,
contentType: false,
processData: false
});
See this article for reference:
Header set Access-Control-Allow-Origin in .htaccess doesn't work
Be careful on:
Header add Access-Control-Allow-Origin "*"
This is not judicious at all to grant access to everybody. It's preferable to allow a list of know trusted host only...
Header add Access-Control-Allow-Origin "http://aaa.example"
Header add Access-Control-Allow-Origin "http://bbb.example"
Header add Access-Control-Allow-Origin "http://ccc.example"
Regards,
I activated the Apache module headers a2enmod headers, and the issue has been solved.
Try this in the .htaccess of the external root folder
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>
Be careful with doing Header add Access-Control-Allow-Origin "*" This is not judicious at all to grant access to everybody. I think you should user:
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "http://example.com"
</IfModule>
I +1'd Miro's answer for the link to the header-checker site http://www.webconfs.com/http-header-check.php. It pops up an obnoxious ad every time you use it, but it is, nevertheless, very useful for verifying the presence of the Access-Control-Allow-Origin header.
I'm reading a .json file from the javascript on my web page. I found that adding the following to my .htaccess file fixed the problem when viewing my web page in IE 11 (version 11.447.14393.0):
<FilesMatch "\.(json)$">
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>
</FilesMatch>
I also added the following to /etc/httpd.conf (Apache's configuration file):
AllowOverride All
The header-checker site verified that the Access-Control-Allow-Origin header is now being sent (thanks, Miro!).
However, Firefox 50.0.2, Opera 41.0.2353.69, and Edge 38.14393.0.0 all fetch the file anyhow, even without the Access-Control-Allow-Origin header. (Note: they might be checking IP addresses, since the two domains I was using are both hosted on the same server, at the same IPv4 address.)
However, Chrome 54.0.2840.99 m (64-bit) ignores the Access-Control-Allow-Origin header and fails anyhow, erroneously reporting:
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin '{mydomain}' is therefore not allowed access.
I think this has got to be some sort of "first." IE is working correctly; Chrome, Firefox, Opera and Edge are all buggy; and Chrome is the worst. Isn't that the exact opposite of the usual case?
After spending half a day with nothing working.
Using a header check service though everything was working.
The firewall at work was stripping them
try this:
<IfModule mod_headers.c>
Header set Access-Control-Allow-Credentials true
Header set Access-Control-Allow-Origin "your domain"
Header set Access-Control-Allow-Headers "X-Requested-With"
</IfModule>
It's preferable to allow a list of know trusted host.
If anyone else is trying this, the most upvoted answer should work. However, if you are having issues it could be possible the browser has cached the REQUEST. To confirm append a query string.
To complete the most upvoted answer, I want to add the case whenever the options to the header is not add in a response request, you could add the always keyword from Apache.
In my case i needed to add the access control allow origin in the response of the redirection and not in the result of the redirection.
And a redirection is giving the 302 code status so the header wasn't filled with the correct information.
In this case I needed to add it :
Header always set Access-Control-Allow-Origin "*"
For more information you can check this thread :
Apache: difference between "Header always set" and "Header set"?