40

How do I allow multiple domains for CORS in express in a simplified way.

I have

 cors: {
        origin: "www.one.com";
    }

    app.all('*', function(req, res, next) {
            res.header("Access-Control-Allow-Origin", cors.origin);
            res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
            next();
        });

This works when there is only one domain mentioned in origin

But if I want to have origin as an array of domains and I want to allow CORS for all the domains in the origin array, I would have something like this -

cors: {
            origin: ["www.one.com","www.two.com","www.three.com"];
        }

But then the problem is this below code would not work -

app.all('*', function(req, res, next) {
                res.header("Access-Control-Allow-Origin", cors.origin);
                res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
                next();
            });

How do I make res.header take an array of domains via cors.origin ?

Ajey
  • 7,924
  • 12
  • 62
  • 86
  • what's the problem with using "*" instead of a domain or two? – dandavis Nov 18 '14 at 07:40
  • 8
    * would not put any CORS filter. * would basically allow all domain which I clearly do not want. – Ajey Nov 18 '14 at 17:51
  • 1
    just remember the cors only affects browsers, so security has nothing to do with cors. – dandavis Nov 18 '14 at 22:17
  • Yes agreed, but is it a good practice to put * ? – Ajey Nov 19 '14 at 05:48
  • using "\*" makes it easier to scale and move stuff around later without hard-coding domains. i don't know of any major downsides, and anyone can still use JS to ping your server and show your images/videos without CORS. with postMessage(), "*" is a bad idea, but with CORS it's groovy. – dandavis Nov 19 '14 at 07:04
  • @dandavis cors does only affect browsers so its security concern is for the user, not your server – tim-phillips Oct 22 '17 at 18:41
  • 5
    @dandavis Your comments were made 5 years ago, so your views may have changed, but for future readers, CORS _is_ about security. It's the first line of defense against cross site request forgery if you're using cookies (that's why browsers block cross origin requests by default). The "*" policy means any site can make a request as your user (assuming no other CSRF mitigations). If that user is an admin on your service, a malicious site can do a lot of damage. – kevlened Jul 25 '19 at 00:03

6 Answers6

41

I would recommend the cors-module: https://www.npmjs.org/package/cors It does this kind of stuff for you - check the "Configuring CORS w/ Dynamic Origin"-Section

Agney
  • 18,522
  • 7
  • 57
  • 75
Johannes Reuter
  • 3,501
  • 19
  • 20
  • 2
    Is it necessary to use a module? I am looking for a native solution. – Ajey Nov 18 '14 at 06:55
  • 22
    @Ajey - a module is just code someone else already wrote to solve your problem. In nodejs programming, the large library of open source modules are one of the great advantages - it would be a shame to ignore them. If you want, you can browse the CORS module on github to look at the code to see what it does. The code is [here](https://github.com/troygoode/node-cors/blob/master/lib/index.js). – jfriend00 Nov 18 '14 at 07:13
  • @Johannes - I used the npm module. Thank you. – Ajey Nov 19 '14 at 05:51
  • @Ajey - good decision :) would you mind to approve my answer since you accepted it? – Johannes Reuter Nov 20 '14 at 06:28
  • 2
    The module is now part of express, you can see the docs mentioned in this answer at https://expressjs.com/en/resources/middleware/cors.html#configuring-cors-w-dynamic-origin – Robin Métral Nov 06 '19 at 22:04
  • 1
    ...and also, you can now add multiple URLs as CORS origins as an array - see the [configuration options](https://expressjs.com/en/resources/middleware/cors.html#configuration-options) – Robin Métral Nov 06 '19 at 22:07
35

The value of Access-Control-Allow-Origin must be a string, not a list. So to make it dynamic you need to get the requesting origin from the Origin HTTP request header, check it against your array of authorized origins. If it's present, then add that origin as the value of the Access-Control-Allow-Origin header; otherwise, use a default value, which would prohibit unauthorized domains from accessing the API.

There is no native implementation for this. You can do it yourself using the code below.

cors: {
  origin: ["www.one.com","www.two.com","www.three.com"],
  default: "www.one.com"
}

app.all('*', function(req, res, next) {
  const origin = cors.origin.includes(req.header('origin').toLowerCase()) ? req.headers.origin : cors.default;
  res.header("Access-Control-Allow-Origin", origin);
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});
KernelDeimos
  • 503
  • 4
  • 12
Ashrith
  • 655
  • 8
  • 20
  • if you go to jquery.com and in the developers tools console make a `$.ajax` to `www.one.com`, what value you get on `req.header('host')`?, in my tests I get `www.one.com` wich would make the check think that this is an allowed domain, can anyone confirm this or clarify what is wrong in my test? – Felipe Pereira Jan 15 '15 at 13:29
  • Change `req.header('host')` to `req.header('origin')` – Nop Jiarathanakul Apr 05 '16 at 23:19
17

Using Node, cors middleware, make sure you leave the / off the url, OR ELSE cors could fail if the url in the browser is displayed without it. I.e.

var corsOptions = {
origin: ["http://www.example.com/","http://localhost:3000"],
optionsSuccessStatus: 200 // For legacy browser support
}

app.use(cors(corsOptions));

Failed and would give me the cors error because the browser would display/read the url as http://www.example.com, where below worked and is more inclusive and should work for http://www.example.com and anything beyond that, i.e. http://www.example.com/ or http://www.example.com/blogs/1, etc

var corsOptions = {
origin: ["http://www.example.com","http://localhost:3000"],
optionsSuccessStatus: 200 // For legacy browser support
}

app.use(cors(corsOptions)); 
DeltaPng
  • 505
  • 4
  • 6
8

Simplest way

const cors = require("cors");
app.use(cors({ origin: ["http://localhost:3000", "https://origin2.com"] }));

This will allow request from localhost:3000 and origin2.com

Abraham
  • 12,140
  • 4
  • 56
  • 92
5

In fact, Access-Control-Allow-Origin header should be the same value as the Origin header as long as you want to allow it.

So base on your code just

cors: {
    origin: ["www.one.com","www.two.com","www.three.com"]
}



app.all('*', function(req, res, next) {
            let origin = req.headers.origin;
            if(cors.origin.indexOf(origin) >= 0){
                res.header("Access-Control-Allow-Origin", origin);
            }         
            res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
            next();
        });
lugy90
  • 81
  • 1
  • 5
  • @nameless Nice thought, but that domain wouldn't be allowed: `["www.one.com","www.two.com","www.three.com"].indexOf("https://www.one.com.my.malicious.site.com") === -1` – kevlened Jul 25 '19 at 00:14
2

Hi i want to share my solution: !!! These code works if you are using a remote server and developing on localhost (webpack or another dev environment) Cheers!!

let ALLOWED_ORIGINS = ["http://serverabc.com", "http://localhost:8080"];
app.use((req, res, next) => {
    let origin = req.headers.origin;
    let theOrigin = (ALLOWED_ORIGINS.indexOf(origin) >= 0) ? origin : ALLOWED_ORIGINS[0];
    res.header("Access-Control-Allow-Origin", theOrigin);
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");

    next();
})