Node CORS issues with chrome 85 - node.js

Since Chrome 85, this error occurs when my front (localhost:8080) send a request to my back (localhost:3000, node app) : 'has been blocked by CORS policy: Cannot parse Access-Control-Allow-Headers response header field in preflight response'
And after playing with my CORS policy in my back, it reveals that when I remove headers with a '/' or a '=', everything works well.
Exemple :
// does not work
res.header(
'Access-Control-Allow-Headers',
'Content-Type, Authorization, Content-Length, application/json, charset=utf-8, X-Requested-With'
)
// works well
res.header(
'Access-Control-Allow-Headers',
'Content-Type, Authorization, Content-Lengths, X-Requested-With'
)
And I do not understand the why.
NB : I read https://www.chromium.org/Home/chromium-security/extension-content-script-fetches, I guess it has something to do with my issue but I still could not manage to fix it.

Related

why RESTapi Node working only in browser?

I recently tried to implement a nodejs api. It works very well on localhost, however, I went up to production using several different services, in all of them the same problem happened:
My api returns correctly in the browser,** but it doesn't work calling in the frontend or by postman**... I've already added all possible headers and nothing works, I suspected it was because it wasn't a secure connection (https), but even disabling it in the browser, still not working... someone help me please?
added headers on api:
res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization"); res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); res.header("Accept", "application/json"); res.header("Referrer-Policy","no-referrer")
added headers on frontend:
Accept: 'application/json', 'Content-Type': 'application/json',

How to solve CORS error in NodeJS independent of CORS middleware

I am facing a CORS error when trying to make a request from the client to a node server. I want to solve the issue independent of the CORS middleware. Here is the server-side code. Please let me know if I am missing something. Thanks.
const express = require("express");
const app = express();
app.get("/", (req, res) => {
res.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:5500");
res.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT");
res.setHeader("Access-Control-Allow-Headers", "application/json");
res.send("<h1>Server is running at port 3000!<h1>");
});
app.listen(3000);
The error on the console:
Access to fetch at 'http://localhost:3000/' from origin 'http://127.0.0.1:5500' 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. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
The error message you get on the console says this:
Response to preflight request doesn't pass access control check
That means that the type of requests you are sending is not a "simple" request and requires server pre-flight. Pre-flight is where the browser sends an OPTIONS request with some details about the type of request it wants to send. The server then must respond to that OPTIONS request with the right CORs info before the browser will treat the request as approved and send the actual request.
To response to a pre-flight request, you must handle an incoming OPTIONS request (not a GET or POST or PUT, but OPTIONS). This is the browser asking your server if this request would be OK to send. You can read more about pre-flight requests here on MDN. And, you can read about the difference between simple requests and pre-flighted requests here on MDN.
To code your server to accept the pre-flighted request, you could do something like this:
app.options("/", (req, res) => {
res.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:5500");
res.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT");
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
res.sendStatus(204);
});
Depending upon what exactly the pre-flighted request is (what content-type, what method, etc...) you may need to specify additional options here. You don't show the code for the request in question here so we can't offer more specific details on that request.
Also, where you have this:
res.setHeader("Access-Control-Allow-Headers", "application/json");
that doesn't really make sense because "application/json" is a content-type, not a header. Perhaps you meant this:
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
Simple Requests
This is all spelled out in one of the above MDN references, but a Simple Request that does not require CORs pre-flight, meets the following criteria:
Http method is GET, HEAD or POST
Manually set headers on the request (apart from what the browser sets automatically) are no more than Accept, Accept-Language, Content-Language and Content-Type.
Content-Type can only be application/x-www-form-urlencoded, multipart/form-data or text/plain
Any request that doesn't meet these simple rules will require pre-flight. So, for example, if you were setting the Content-Type to application/json, that would immediately cause pre-flight because that's not one of the permitted content-types for non-preflighted requests. If your request was a GET, then there's no need to set content-type at all since you aren't sending any content with the request.
const corsOpts = {
origin: '*',
methods: [
'GET',
'POST',
],
allowedHeaders: [
'Content-Type',
],
};
app.use(cors(corsOpts));
OR you can use
app.use(function(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});

Mobile only CORS Error: Origin is not allowed by Access-Control-Allow-Origin In Node.js

I've set up a Node.js (TypeScript hosted on Google Cloud Platform [GCP]) app for CORS but I'm still getting errors (Origin is not allowed by Access-Control-Allow-Origin) on mobile--desktop works fine.
I've searched but there are so many questions about getting this set up in general, I can't find why it specifically isn't working for mobile.
this.app.use(cors());
this.app.options('*', cors());
...
router.use(function(req, res, next) {
res.header('Content-Type', 'application/json');
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'DELETE,GET,OPTIONS,PATCH,POST');
res.setHeader('Access-Control-Allow-Headers', 'Origin, Accept, Authorization, Content-Type, X-Requested-With, Access-Control-Allow-Headers, Access-Control-Request-Method, Access-Control-Request-Headers');
next();
});
BTW The errors don't appear in the console until a few minutes after the page has loaded. (I've removed the URLs which are valid.)
"XMLHttpRequest cannot load due to access control checks."
"Failed to load resource: Origin is not allowed by Access-Control-Allow-Origin."
The issue was missing data in the DB, so the Node endpoint was not returning properly. The errors had nothing to do with the problem.

“Access-Control-Allow-Origin header contains multiple values” error

I'm getting mirriad of errors trying to do an ajax call in a reactjs app using axios. I have an api that lives at a subdomain and making calls from the main domain.
.htaccess:
Header add Access-Control-Allow-Origin: "*"
Header add Access-Control-Allow-Credentials: "true"
Header add Access-Control-Allow-Methods: "GET,HEAD,OPTIONS,POST,PUT"
Header add Access-Control-Allow-Headers: "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers"
ajax headers in reactjs (using axios):
var options = {
method: 'GET',
url: 'http://admin.mysite.com/menus/5',
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET,HEAD,OPTIONS,POST,PUT',
'Access-Control-Allow-Headers': 'Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers'
}
}
I've tried making changes to each of these but get different errors. If I have the Header add Access-Control-Allow-Origin: "*" it complains about double origins. If I remove it I I get an error about Access-Control-Allow-Origin is not allowed by Access-Control-Allow-Headers in preflight response other changes has responded with Access-Control-Allow-Headers is not allowed by Access-Control-Allow-Headers in preflight response
I'm using wordpress as a headless CMS and tapping into the restful api to pull the data I need. I have noticed if I removed all of this I can get my data fine but I can't post without fixing the cross domain issues.
If I remove it I I get an error about Access-Control-Allow-Origin is not allowed by Access-Control-Allow-Headers in preflight response other changes has responded with Access-Control-Allow-Headers is not allowed by Access-Control-Allow-Headers in preflight response
Both those error messages are happening because in your frontend JavaScript code you have this:
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET,HEAD,OPTIONS,POST,PUT',
'Access-Control-Allow-Headers': 'Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers'
}
You need to remove that entire headers option from your request code.
The reason is, all the Access-Control-Allow-* headers are response headers that servers must return. The only effect you’ll have by sending them as request headers is to cause exactly the kinds of errors cited in the question.
If the reason you’re adding them is that your .htaccess settings on the server side for the API endpoint you’re sending the request to aren’t making the server send the right response headers, then you need to figure that out and fix that on the server side. Sending additional request headers from the client side isn’t going to fix that problem.
One suggestion you might try for your .htaccess: instead of Header add, use Header set:
Header set Access-Control-Allow-Origin: "*"
Header set Access-Control-Allow-Credentials: "true"
Header set Access-Control-Allow-Methods: "GET,HEAD,OPTIONS,POST,PUT"
Header set Access-Control-Allow-Headers: "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers"
Header set tells Apache to overwrite/clobber any existing value that might already be a set for a particular header, whereas Header add tells it to just add a header with the name and value given, without overwriting any header that might already be set with that name.
So Header add can cause multiple headers with the same name to be sent in a response, in which case the browser treats it as a single header with multiple values. You don’t want that.

AngularJS cross domain request to separate ExpressJS App hosted on Heroku

I have a stand-alone ExpressJS API that I have built that should be able to service mobile apps and web apps. I'm trying to test the API using a simple AngularJS client app that I have built. The API service runs fine when I host it locally.
I'm getting Cross Domain Request errors when trying to make a GET call to the API hosted on my external server. I'm using Chrome v39
EDIT: my error turns out to be an incorrect URL reference to my heroku API. Please see my answer, below.
XMLHttpRequest cannot load http://myservice.heroku.com/some-api-endpoint?request-parameter=value. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin http://localhost:5001 is therefore not allowed access.
After reading and scanning numerous articles, I've tried the following:
CORS Code on the API
Added to app.js
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
res.header("Access-Control-Allow-Headers", "Cache-Control, Pragma, Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Max-Age", "1728000");
res.header("Access-Control-Expose-Headers", "Cache-Control, Pragma, Origin, X-Requested-With, Content-Type, Accept");
if (req.method === 'OPTIONS') {
res.statusCode = 204;
return res.end();
} else {
return next();
}
});
CORS Code on the API (Attempt 2)
Using the CORS node_module instead of the above, yields the same errors
Added to Package.json
"cors" : "~2.5.2"
Added to app.js
var cors = require('cors');
app.use(cors());
Client Code (Attempt 1)
$http({
url: 'http://myservice.heroku.com/some-api-endpoint?request-parameter=value',
method: 'GET',
headers : {
"Origin" : "myclient.heroku.com",
"Access-Control-Expose-Headers": "X-Requested-With",
"Access-Control-Request-Method" : "GET",
"Access-Control-Request-Headers" : "Origin, X-Requested-With, Content-Type, Accept"
}
})
Errors in the chrome dev console:
Refused to set unsafe header "Origin" angular.js:9625
Refused to set unsafe header "Access-Control-Request-Method" angular.js:9625
Refused to set unsafe header "Access-Control-Request-Headers" angular.js:9625
XMLHttpRequest cannot load http://myservice.heroku.com/some-api-endpoint?request-parameter=value, which is disallowed for cross-origin requests that require preflight. (index):1
Client Code (Attempt 2)
thePath = 'http://myservice.heroku.com/some-api-endpoint?request-parameter=value'
+'&callback=JSON_CALLBACK';
$http.jsonp(thePath)
.success(function(data){
console.log(data);
});
Errors received in the Chrome Dev Console:
Uncaught SyntaxError: Unexpected token : endpoint?request-parameter=value&callback=angular.callbacks_0:1
This has been stumping me for two days. Any help is appreciated!
The error turned out to be the reference to applications hosted on Heroku. I was attempting to make my get requests to myapp.heroku.com and not myapp.herokuapp.com. This is a subtle difference that caused there error.
Using cURL or typing in the request into the browser's address bar for myapp.heroku.com will redirect your request to myapp.herokuapp.com and complete the request successfully. However, made from Angular.js $http() function resulted in the Cross Domain error.
The simplest problems seem to cause the most confusion.
You are taking a convoluted route for CORS. Use nodejs CORS middleware to do your stuff....
add,
"cors": "^2.5.1",
to your dependencies in package.json & in app module,
var cors = require('cors');
//add cors to do the cross site requests
app.use(cors());

Resources