nodejs cross-origin read blocking issue with image resources and canvas - node.js

I have a nodejs application were cors setup is done using cors package from expressjs.
My cors setup code is :
var whitelist = ['https://shajao.com', 'https://www.shajao.com'];
var corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
},
allowedHeaders: ['Content-Type', 'Authorization', 'Content-Length', 'X-Requested-With', 'Accept'],
methods: ['GET', 'PUT', 'POST', 'DELETE', 'OPTIONS'],
optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
}
app.use(cors(corsOptions));
app.use(express.static(path.join(__dirname, '/public/')));
apis are called from an angular application which is getting server reponses perfectly. So cors is working nicely here. But image resources are getting blocked by cors.
Url to visit if you want to see the problem :
https://shajao.com/frames
Sample image url: https://api.shajao.com/uploads/frames/8cf9006f-0225-461b-a4f2-153737152274.png

Cross-Origin Read Blocking (CORB) is a new web platform security feature.
Ref : https://www.chromium.org/Home/chromium-security/corb-for-developers
Try clearing browser's cache first.
If it doesn't work you will have to set the correct "Content-Type" header for the response.

Related

Unable to connect to GraphQL API with fetch, getting CORS error

I've been reading posts about CORS the last two days, and tried every?.. combination of tips, but still can't get this working.
I used Node and installed 'graphql', 'express' and 'express-graphql'.
The GraphiQL GUI page works fine. Server running at :6969
Then I have a web-server that I also installed with Node for my front-end running at :8000
It's installed globally with -g. I'd be amazed it matters thought. And when I try to make requests to the API I get this error in my browser:
Access to fetch at 'http://127.0.0.1:6969/graphql' from origin
'http://127.0.0.1:8000' 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.
Why am I getting CORS errors when they have the same origin? Because they are listed at different ports?
I have tried installing an configuring 'cors' in my GraphQL-server. It didn't change anything.
I have tried modifying my request using:
mode: 'no-cors'
which only give me: 400 Bad request. I believe an opaque response is not what I want anyway.
And I have tried adding these to my request.
mode: 'cors'
credentials: 'include',
I have also tried modifying the header. This is the different headers I have tried:
let headers = new Headers()
headers.append('Content-Type', 'application/json')
headers.append('Accept', 'application/json')
headers.append('Origin',' http://127.0.0.1:6969/graphql')
headers.append('Access-Control-Allow-Origin', 'http://127.0.0.1:6969/graphql')
headers.append('Access-Control-Allow-Origin', '*')
headers.append('Access-Control-Allow-Credentials', 'true')
headers.append('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept')
I have also tried accessing from different IP's but I still can't escape this error.
I just don't understand where the "crossing" is supposed to be?
Here is the rest of my request:
...
fetch(' http://127.0.0.1:6969/graphql', {
// mode: 'cors',
// mode: 'no-cors',
credentials: 'include',
method: 'POST',
headers: headers,
// headers: {'Content-Type': 'application/json'},
body: JSON.stringify(requestBody),
})
.then(res => {
if (res.status !== 200 && res.status !== 201) {
throw new Error('Failed HTTP request!')
}
return res.json()
})
.then(resData => {
window.thisDiv.innerHTML = resData.data
})
.catch(err => {
window.thisDiv.innerHTML = `Server error! ${err}`
})
}
I found a better solution now.
The cors-package I installed was never used because I applied the cors code after I started the server. I just needed to swap those app.use() statements and it worked.
//...
const cors = require('cors')
const corsOptions = {
origin: '*',
methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
accessControlAllowOrigin: '*',
accessControlAllowCredentials: true,
}
app.use(cors(corsOptions))
app.use('/graphql', graphqlHTTP({
schema,
graphiql: true
}))
I found a temporary solution by Aditya Patnaik in a thread about CORS and localhost.
Just Run this line:
Disable web security and site isolation trials in Chrome
chrome.exe --disable-site-isolation-trials --disable-web-security --user-data-dir="PATH_TO_PROJECT_DIRECTORY"
PS: chrome added around 800 files and 300 folder to my directory. I'm still looking for a simpler solution where I only change the appropriate header or make the cors package work.

Koa + Node.JS RESTful API Cors preflight origin error after transferring from local to host

I know there are a lot of articles out there regarding the cors preflight error:
http://70.xx.xx.60/oms/api/login' from origin 'http://order.example.com' 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.
However, I had this issue once when I was developing in my local environment, fixed it, and when I moved my server to a host (A2Hosting), despite enabling cors in the .htaccess file like they recommend, I have returned to getting this error. The following are the relevant files if anyone could take a look and offer insight as to why this issue has popped up again after being resolved once. I am not looking to download the chrome plugin workaround, and I would like to avoid a proxy, I'd prefer to just setup cors correctly and forget about it.
my server.js:
require("dotenv").config();
const Koa = require("koa");
const cors = require("#koa/cors");
const Router = require("koa-router");
const bodyParser = require("koa-bodyparser");
const baseRoutes = require("./routes");
const serve = require('koa-static');
const PORT = 30500;
const app = new Koa();
var options = {
origin: '*',
allowMethods: ['GET', 'POST', 'DELETE', 'PUT', 'OPTIONS', 'PATCH'],
allowHeaders: '*',
credentials: true
}
app.use(cors(options));
app.use(bodyParser());
app.use(baseRoutes.routes());
app.use(serve('./assets'));
app.listen(PORT, () => {
console.log(`Server listening on ${PORT}`);
});
my call from the frontend (in this example the login page at index.html)
async function postData(url = "", data = {}) {
// Default options are marked with *
return await fetch(url, {
method: "POST", // *GET, POST, PUT, DELETE, etc.
mode: "cors", // no-cors, *cors, same-origin
cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
credentials: "omit", // include, *same-origin, omit
headers: {
"Content-Type": "application/json"
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: "follow", // manual, *follow, error
referrerPolicy: "no-referrer", // no-referrer, *client
body: JSON.stringify(data) // body data type must match "Content-Type" header
});
}
If you need to see more info, please let me know and I will provide it.
I resolved this by changing the POST request URL from the IP version of the website to the human readable URL. I feel dumb, but I will leave this up for other people who make a similar mistake.

What to include in headers when making preflight complex CORS request?

An app I'm making has the front-end and node-back end hosted separately (cross origin). The front-end is making a call to the back end for login where the x-session-token is sent back. Because this is a custom header I understand this to be a complex request and therefore a pre-flight check is needed.
In the server.js file I have the following snippet (which I understand to enable CORS pre-flight checks):
const express = require('express');
const cors = require("cors");
const app = express();
const corsOptions = {
origin: true,
credentials: true
}
app.options('*', cors(corsOptions));
The front-end makes the following axios call:
axios.post('/api/user/login', logInObj,
{withCredentials:true},
{crossDomain:true},
{'Access-Control-Request-Headers': 'Content-Type'},
{'Access-Control-Request-Method': 'post'}
)
.then(logInResponse => ...
Which is responded to by this in the back-end:
router.post('/api/user/login', (request, response) => {
...
response.setHeader('Access-Control-Allow-Credentials', true);
response.setHeader('Access-Control-Allow-Headers', 'Content-Type');
response.setHeader('Access-Control-Allow-Method', 'get', 'post', 'options');
response.setHeader('Access-Control-Allow-Origin', request.get('Origin'));
response.setHeader('Access-Control-Max-Age','86400')
response.setHeader('Access-Control-Expose-Headers', 'Access-Control-Allow-Origin');
...
When I console log the response header on the back-end it contains:
An x-session-token matches that in MySQL
Access-Control-Allow-Origin is listed as http://localhost:3000 not wildcard (*)
However the console.log of the response in the browser has null for the session-token which tells me the browser is blocking the CORS return data (X-Session-Token in this case). What am I missing in the request or response header?
I think you miss the exposed Header you want to send back.
"x-session-token" ?
Also try to use app.use instead of just app.options and let the cors package handle it unless it is just specific to this route of course
app.use(cors({
credentials: true,
exposedHeaders: ['Set-Cookie', 'Content-Length', 'Accept', 'X-Requested-With', 'X-HTTP-Method-Override', 'x-session-token' ],
methods: ['GET', 'POST', 'OPTIONS', 'HEAD'],
optionsSuccessStatus: 204,
origin: 'http://localhost:3000'
})

express JS cors middleware does not work when server is accessed though fetch request

Server is on http://localhost:3001, and client is same, but with port 3000.
On client I run simple fetch, I need to get logged-in user data from server, and currently I am doing it just using GET method(GET, POST, none work) like this(I also have to include cookies):
fetch("http://localhost:3001/user", {
method: "GET",
credentials: "include",
headers: {
"Content-Type": "application/json"
}
}).then(response => {
console.log(response);
});
And the server:
const cors = require("cors");
var corsOptions = {
origin: "http://localhost:3000",
optionsSuccessStatus: 200
};
app.get("/user", cors(corsOptions), function(req, res, next) {
u_session = req.session;
const db_result = db
.collection("users")
.findOne({ email: u_session.email }, function(err, result) {
if (err) throw err;
res.json({ email: result.email, type: result.type });
});
});
What I get is cors error:
Access to fetch at 'http://localhost:3001/user' from origin 'http://localhost:3000' 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.
Also if i go to server URL through browser, I can see access-allow-control-allow-origin header set successfully.
Also as requested, screenshot of failed case network tab:
I've searched plenty of solutions on the internet, nothing seems to work. Am I missing something?
Thanks for any help.
Ensure that if you have a proxy set that it is set to http://localhost:3001. After that adjust your fetch to only use a partial url like so:
fetch("/user", {
method: "GET",
headers: {
"Content-Type": "application/json"
}
}).then(response => {
console.log(response);
});
it should be safe to remove this as well:
const cors = require("cors");
var corsOptions = {
origin: "http://localhost:3000",
optionsSuccessStatus: 200
};
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
What sticks out to me is "preflight". I think it may be the OPTIONS request that doesn't have the correct CORS headers enabled. Ensure that you're enabling CORS on GET, POST, OPTIONS, and any other method your API supports.
Since you send credentials from the client, you must configure your cors module to allow credentials via athecredentials property. Also, application/json is a non-simple Content-Type, so you must allow that explicitly via allowedHeaders:
var corsOptions = {
origin: "http://localhost:3000",
optionsSuccessStatus: 200,
credentials: true,
allowedHeaders: ["Content-Type"]
};
Without this, the server will not include a Access-Control-Allow-Credentials header in the OPTIONS preflight, and the browser will refuse to send the main GET request.

Enabled CORS in node/express but getting "Response to preflight request doesn't pass access control check"

I am getting the error :
Failed to load http://localhost:3000/users/register: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.
On the front end i'm using axios:
const instance = axios.create({
baseURL: 'http://localhost:3000',
timeout: 1000,
headers: {"Access-Control-Allow-Origin": "*"}
});
instance.post('/users/register').then((res) => {
console.log(res);
}).catch((err) => {
console.log(err);
});
and on the server-side using express i am using cors:
var cors = require('cors');
var corsOptions = {
origin: '*',
optionsSuccessStatus: 200
}
app.use(cors(corsOptions));
I am getting a response code of 200 and I do see the 'Access-Control-Allow-Origin' header but i'm not getting anything on the server-side. Any ideas?
You most likely need to also explicitly enable support for OPTIONS requests (i.e. "CORS preflight"). See https://github.com/expressjs/cors#enabling-cors-pre-flight for details on how to do that.
For your specific case, I would add the following:
app.options('/users/register', cors(corsOptions));
Or if you want to enable it for all requests:
app.options('*', cors(corsOptions));

Resources