NodeJS - CORS middleware `origin` undefined - javascript

I have an app using the cors npm package as middleware. I have it set up like this:
if(process.env.NODE_ENV === 'production') {
var whitelist = ['http://mywebsite.com', 'https://mywebsite.com']
var corsOptions = {
origin: (origin, callback) => {
var originIsWhitelisted = whitelist.indexOf(origin) !== -1;
console.log('ORIGIN: ', origin); // => undefined
callback(originIsWhitelisted ? null : 'Bad Request', originIsWhitelisted)
},
credentials:true
}
app.use(cors(corsOptions));
}
The origin parameter in my corsOptions is undefined. Why is this and how can I fix it?

If you do not want to block REST tools or server-to-server requests, add a !origin check in the origin function like so:
var corsOptions = {
origin: function (origin, callback) {
if (!origin || whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}

This happens when you load your page in the same origin that you are making API calls to. The browser doesn't set the "Origin" header unless the API call's domain is different from the one where the page is being served.
This is further explained here https://github.com/expressjs/cors/issues/113
If you make your API call using the browser console, from within a different website, you'll see that the browser sets the Origin header, and thus it will not be undefined when read by express.
You can account for this by using
if (whitelist.indexOf(origin) !== -1 || !origin)

use is a method to configure the middleware .You must apply the corsoptions in the route only. This is what i'm see based on the documentation. Not tested it yet. Hope it'll help yaa.
var whitelist = ['http://example1.com', 'http://example2.com']
var corsOptions = {
origin: function (origin, callback) {
var originIsWhitelisted = whitelist.indexOf(origin) !== -1
callback(originIsWhitelisted ? null : 'Bad Request', originIsWhitelisted)
}
}
app.get('/products/:id', cors(corsOptions), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for a whitelisted domain.'})
})

Related

CORS settings in router.get() Express.js

I have a white list of URLs
I have trouble using it with GET requests, but with POST it works.
For POST everything works.
For GET I took an example from the Express website. It doesn't work. Cors allowed GET requests from any domain.
const allowedList =["http://localhost:3000", "http://localhost:3001"]
const corsOptions = {
origin: function (origin, callback) {
if (allowedList.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}
const corsOptionsGet = function (req, callback) {
let corsOptions;
if (allowedList.indexOf(req.header('Origin')) !== -1) {
corsOptions = { origin: true }
} else {
corsOptions = { origin: false }
}
callback(null, corsOptions)
}
router.post("/add-item", cors(corsOptions), addItem);
router.get("/get-item", cors(corsOptionsGet), getItem);
How are you calling your server? if you are using tools like Postman or curl the Origin header is not set by default and you need to manually add it to the request header.

cors package send status instead of error

I am trying to use cors package in node and express environment to verify if requesting domain can access my resources. That part was not a problem following official documentation. The problem however is with response. If domain is not allowed to access - cors is sending error with stack trace (paths to files). Can this be avoided and just respond with status 401, something like res.status(401).end() ? I tried that but it gives me error because headers were already sent.
const cors = require("cors");
const corsOptions = async (req, callback) => {
let domain = getDomain(req);
if (domain === false) {
return callback(new Error("Not allowed by CORS"));
}
const isWhitelisted = await client.get(domain).catch(err => { console.log(err); });
if (isWhitelisted !== undefined) {
callback(null, true);
} else {
callback(new Error("Not allowed by CORS"));
}
};
app.use(cors(corsOptions));
So i was hoping to replace callback(new Error("Not allowed by CORS")); this part with just sending status 401 and ending stream so no errors with stack are printed in the client.
It can't be done, according to the source code what you are sending in callback as err is passed in the next function like
if(err) next(err);
But there is one easy workaround to what you want.
The cors() is returning a middleware(a function with three params req, res and next). So you can wrap the cors in your middleware and return whatever you want. If all the things are perfect you can use the cors.
const app = require('express')();
const cors = require("cors");
const corsMid = (req, res, next)=>{
const trueVal = true;
if(trueVal){
res.status(400).send("Error")
}else{
return cors()(req,res,next);
}
}
app.use(corsMid);
app.get('/', (req, res)=>{
res.json('Hello World');
})
app.listen(8080, ()=>{
console.log('started')
})
I found a workaround is you can construct the Error on a variable first, then remove the stack property from the error variable:
let err = new Error('Not allowed by CORS')
err.stack = ""
callback(err)
Hope this help!

How to allow specific domain to access cloud functions

I am using firebase cloud functions and at the first time I saw cors then set origin to true.. but in that way anyone can access to my functions, so I looked a way to allow only specific domains to access my cloud functions, I got the code from cors github page and tried it, but I get unexpectedly closed the connection after waiting and waiting.
here is my function index.js --
const functions = require('firebase-functions');
const cors = require('cors');
var whitelist = ['http://example1.com', 'http://example2.com']
var corsOptionsDelegate = function (req, callback) {
var corsOptions;
if (whitelist.indexOf(req.header('Origin')) !== -1) {
corsOptions = { origin: true } // reflect (enable) the requested origin in the CORS response
}else{
corsOptions = { origin: false } // disable CORS for this request
}
callback(null, corsOptions) // callback expects two parameters: error and options
}
exports.api = functions.https.onRequest((req, res) => {
cors(req, res, () => {
var d = new Date();
var n = d.getHours();
if (n > 8 && n < 17) {
res.status(200).send("Get started")
} else {
res.status(200).send("Closed")
}
})
});
With an HTTP triggered function on Firebase Cloud Functions the cors middleware origin parameter will be undefined, as will be the request header Origin value:
var whitelist = ['https://example1.com']
var corsOptions = {
origin: function (origin, callback) {
console.log(origin) // undefined
if (whitelist.indexOf(origin) !== -1) {
callback(null, true)
} else {
callback(new Error('Not allowed by CORS'))
}
}
}
app.get('/products/:id', cors(corsOptions), function (req, res, next) {
console.log(req.header('Origin')) // undefined
res.json({msg: 'This is CORS-enabled for a whitelisted domain.'})
})
unless you set the Origin header yourself when you make the request to the function. For example:
await http.get(
'https://example1.com/yourfunction',
headers: {
"Origin": "https://example2.com",
},
);
The problem is that anyone can write the above request (the Origin header can be faked), so as this post suggests a more fool-proof way to verify access is by sending something like the token that Firebase Auth generates when you sign in (or you can provide the sending party with a secret key they would need to send):
await http.get(
'https://example1.com/yourfunction',
headers: {
"Authorization": "Bearer your_api_token_here",
},
);
You would then verify that it's legit in the Cloud Function (instead of checking the potentially fake origin).

express + cors() is not working properly

I'm building a React application and I'm trying to make a call to https://itunes.apple.com/search?term=jack+johnson
I have a helper called requestHelper.js which looks like :
import 'whatwg-fetch';
function parseJSON(response) {
return response.json();
}
function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response;
}
const error = new Error(response.statusText);
error.response = response;
throw error;
}
export default function request(url, options) {
return fetch(url, options)
.then(checkStatus)
.then(parseJSON);
}
So I get:
XMLHttpRequest cannot load
https://itunes.apple.com/search?term=jack%20johnson. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:3000' is therefore not allowed
access.
My express server looks like this:
const ip = require('ip');
const cors = require('cors');
const path = require('path');
const express = require('express');
const port = process.env.PORT || 3000;
const resolve = require('path').resolve;
const app = express();
app.use(cors());
app.use('/', express.static(resolve(process.cwd(), 'dist')));
app.get('*', function(req, res) {
res.sendFile(path.resolve(resolve(process.cwd(), 'dist'), 'index.html'))
});
// Start app
app.listen(port, (err) => {
if (err) {
console.error(err.message);
return false;
}
const divider = '\n-----------------------------------';
console.log('Server started ✓');
console.log(`Access URLs:${divider}\n
Localhost: http://localhost:${port}
LAN: http://${ip.address()}:${port}
${divider}
`);
});
I have tried using mode: 'no-cors' but is not actually what I need since the response is empty.
Am I doing something wrong with this configuration?
The same origin policy kicks in when code hosted on A makes a request to B.
In this case A is your Express app and B is iTunes.
CORS is used to allow B to grant permission to the code on A to read the response.
You are setting up CORS on A. This does nothing useful since your site cannot grant your client side code permission to read data from a different site.
You need to set it up on B. Since you (presumably) do not work for Apple, you can't do this. Only Apple can grant your client side code permission to read data from its servers.
Read the data with server side code instead.

Node.js cors request - Async example not working

I am using the node-cors module in an app. I've followed some of their examples to make a cors request.
I have a route that I'd like to dynamically add cors options for:
var cors = require('cors'),
user = require('../models/user');
router.get('/route', cors(corsOptions), function(req, res) {...}
This works (this comes straight from one of the examples):
var whitelist = ['http://example1.com', 'http://example2.com'];
var corsOptionsDelegate = function(req, callback){
var corsOptions;
if(whitelist.indexOf(req.header('Origin')) !== -1){
corsOptions = { origin: true, credentials: true }; // reflect (enable) the requested origin in the CORS response
}else{
corsOptions = { origin: false }; // disable CORS for this request
}
callback(null, corsOptions); // callback expects two parameters: error and options
};
This, however, doesn't work and I'm not sure what is wrong:
var corsOptions = function(req, callback){
user.findOne({
url: req.header('Origin')
},function(err,match){
var options;
if(!empty(match)){
options = {
origin:true,
credentials: true
};
}else{
options = {
origin: false,
credentials: false
};
}
callback(null, options);
});
};
Is this an issue with the module, or something I've implemented wrong?
You need to import this:
const cors = require('cors')({origin: true}); instead of const cors = require('cors');

Categories

Resources