How to: enable CORS in express.js (node.js)

Express.js is one of the most popular node.js frameworks for serving websites or building APIs. This article is about how to enable Cross Origin Resource Sharing, also known as CORS. For that we need to set the correct headers in the response, which allow a browser to make use of the data from any domain.

Visit the demo project on github. A complete example is at the bottom of this post.

Update: You can also use the cors module (via reddit comments)

CORS exists for security reasons and to limit which resources a browser can gain access to, from another website. Let's say our site exists at http://someexampledomain.com and we want the JavaScript files on that site to access http://anotherdomain.com, we can't do that unless the server at http://anotherdomain.com allows it.

If we try an AJAX/xmlhttprequest to a file like that, we get an error message from the console in our browser.

Chrome, Chromium:

XMLHttpRequest cannot load http://localhost:3000. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

Firefox:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:3000. (Reason: CORS header 'Access-Control-Allow-Origin' missing).

The CORS rules apply to the same hostname and are also bound to the same port. So if I had an HTML file with JavaScript served by http://localhost:3001 it would not be allowed to load things from http://localhost:3000.

To allow exactly that to happend and have our client side code separate from our server and just make it load data, like with frameworks like Angular, Ember, Backbone or the like, we can use the following middleware function in express before we define our routes:

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

That's it! Now you can access your route from any other domain or even from an HTML file that's just sitting on your computer, without being served by the same or any other web server.

Limit CORS to specific routes

If you only want to serve some routes to clients of all origins, you should set the res.headers specifically for these routes and omit the next(), but just send your response, like in the following example:

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  res.json({data: [1,2,3,4]})
});

With this method you can limit the Cross Origin Resource Sharing headers to specific routes of your API in express.js.

Summary

Now we've been through enabling CORS with node.js and Express.js, which enables you to build an API that can be reached from any browser in the world and not only through the JavaScript files you server from your domain, great job!

If you have any feedback to this guide, please let me know in the comments or one of the various social media channels. Also you can always drop me a mail at something @ this domain dot com.

A complete example of the technique described here can be found at the Demo project on github or just try the paste below:

var express = require('express');

var app = express();
app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

app.get('/', function (req, res) {
  var data = {
    "bestAnimals": [
      "wombat",
      "corgi",
      "puffer fish",
      "owl",
      "crow"
    ]
  };

  res.json(data);
});

var server = app.listen(3000, function () {

  var host = server.address().address;
  var port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);

});
Tagged with: #AJAX #CORS #express.js #node.js #xmlhttprequest

Thank you for reading! If you have any comments, additions or questions, please tweet or toot them at me!