Search code examples
node.jsexpressherokuhttp-headerscors

Restricting CORS origin with Node/Express not working


I'm trying to restrict the origin of CORS requests to one specific domain per route using the express.js CORS package like so:

const express = require('express');
const cors = require('cors');

const port = process.env.PORT || 3000;

let app = express();

app.get('/', cors({origin: 'http://example.com'}), (req, res, next) => {
  res.sendStatus(200);
});

app.post('/', cors({origin: 'http://whatever.com'}) (req, res, next) => {
  res.sendStatus(200);
});

app.listen(port, () => {
  console.log(`Started on port ${port}`);
});

This doesn't seem to have any effect, however, as I'm able to GET and POST from any domain. I then tried instead to restrict all routes to one single origin using the following, but met the same results:

app.use(cors({origin: 'http://example.com'}));

I'm experiencing this both in my dev environment on localhost and my production environment on Heroku. Any idea what I'm missing?


Solution

  • If your server is sending an Access-Control-Allow-Origin: http://example.com response header, then you actually already have it configured correctly.

    It’s expected behavior for the server to return a 200 response no matter what origin you make the request from—even for those from an origin other than the configured http://example.com

    The CORS settings don’t cause the server to block requests from any clients.

    Instead, if the server responds with Access-Control-Allow-Origin: http://example.com to a client request from JavaScript code in a web app that’s not running at http://example.com, then the browser blocks that JavaScript code from being able to access the response.

    https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS gives more details.

    Basically the way it works is that from the server side, no behavior changes other than the difference in what response headers it sends. So the server will receive the request just as it otherwise would, and will send the response just as it otherwise would.

    And then the browser will receive the response just as it otherwise would. You will be able to see the response in your browser devtools and examine it there. But that does not mean the browser will expose the response to your client-side JavaScript code.

    Instead, the browser checks the value of the Access-Control-Allow-Origin response header from the server and will only expose the response cross-origin to your origin if the server says it should be allowed to: Your browser checks the value of the Access-Control-Allow-Origin against your actual origin, and if it either matches exactly or the value is * to allow any origin, only then does the browser allow your client-side JavaScript code to access the response.