7
votes

I'm using Express for my website and using credential xhr. I want to request to http://example.com from http://admin.example.com or http://service1.example.com, and this is my Access-Control-Allow-Origin part in express server:

// CORS
app.use((req, res, next) => {
    res.setHeader('Access-Control-Allow-Origin', 'http://*.example.com');
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,Content-Type');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE');
    next();
});

But when I try credential xhr from http://admin.example.com to http://example.com, it fails with:

Fetch API cannot load http://example.com/api/v1/authentication/signin. Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header has a value 'http://*.example.com' that is not equal to the supplied origin. Origin 'http://admin.example.com' is therefore not allowed access. Have the server send the header with a valid value, or, if an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Looks like it causes from browser didn't understood what exactly *.example.com means, and refuse the request.

I want to request from these domains:

  • example.com
  • admin.example.com
  • service1.example.com
  • service2.example.com
  • [anything].example.com

I'm using Fetch API for XHR, and set credentials: true. Is there a something that I missed? Any advice will very appreciate it.

3

3 Answers

3
votes

First off, IIRC; express documentation explicitly asks you not to use lambda expression for the middlewares.

Coming to the CORS issue, a wildcard subdomain is not valid in the context. The support was added pretty recently (in May '16), and until then, the CORS header must be an exact match of the domain name.

You can however, process your req.hostname value and add that to the response header:

// CORS
app.use(function (req, res, next) {
    if (req.hostname.endsWith('example.com')) {
        res.setHeader('Access-Control-Allow-Origin', 'http://' + req.hostname)
        res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,Content-Type')
        res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE')
    }
    next()
})
5
votes

I agree with Derric's comment. The other thing though is that origin headers can be spoofed, so this is not a secure solution.

app.use(function (req, res, next) {
  if (req.headers.origin.endsWith('example.com')) {
    res.setHeader('Access-Control-Allow-Origin', 'http://' + req.headers.origin)
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,Content-Type')
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE')
  }
  next()
})
1
votes

Adding another small adjustment here. We should also consider "protocol":

app.use(function (req, res, next) {
  if (req.headers.origin.endsWith('example.com')) {
    res.setHeader('Access-Control-Allow-Origin', req.protocol + '://' + req.headers.origin)
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,Content-Type')
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, DELETE')
  }
  next()
})