In this post, we’ll try and understand how CORS works, how to configure an Express.js
server to support CORS and test it using our browser tools. Understanding CORS is crucial for web developers so let’s break it down and get started!!
What is CORS?
CORS, or Cross-Origin Resource Sharing, is a set of rules that allow or restrict the sharing of resources between servers and browsers. Who is responsible, though, for setting up the rules? The server makes the rules, and it’s up to the browser to follow them. Let’s simplify by using an example.
We have a browser loading a page at https://noghostsinside.com
.
This page has a script to be loaded, and because of this, the browser sends a request to a server located at https://api.noghostsinside.com
.
When sending the request, the browser adds an “Origin” header stating the protocol, host, and port (optional) from which the request is made. In our example, it would be Origin
: https://noghostsinside.com
.
When the server receives this request, it will respond with a header called Access-Control-Allow-Origin
.
This header will include all origins that are allowed to load the requested resource; examples of this header’s value could be:
Access-Control-Allow-Origin
:*
– All origins are allowed to load this resource.Access-Control-Allow-Origin
:"https://noghostsinside.com"
– Only requests from this URL are allowed to load this resource.
There is also a chance that there will be no Access-Control-Allow-Origin
header, included in the server’s response headers. The lack of this header makes the browser assume that resource sharing is only allowed from requests from within the same origin – known as Same-origin policy.
When testing your site’s server interaction, there is a good chance you are doing it without using the browser. If you’re using a program like Postman, CORS isn’t automatically applied. This means you might be able to load resources without restriction. To ensure compliance with CORS policies, configure your program to behave like a browser.
Non-browser HTTP clients typically don’t apply CORS unless specifically configured to do so.
How CORS works: exploring with dev tools
To see CORS in action, I have set up a simple server on my machine using Express.js. It responds with a simple object on the /
route.
const express = require('express');
const app = express();
const PORT = 8080;
app.get('/', (req, res) => {
res.send({
name: 'No Ghosts Inside'
});
})
app.listen(PORT, () => {
console.log(`Your app is listening on port ${PORT}`);
})
JavaScriptAfter running this server, I opened my browser in noghostsinside.com blog (not my localhost) and accessed the dev-tools console tab. From there, I executed the following command:
fetch("http://localhost:8080")
.then(res => res.json())
.then(data => console.log({ data }))
This command fetches data from my local server running on port 8080 and logs its response in the console. In case you didn’t already know, by executing this command, I got a CORS error:
Access to fetch at ‘http://localhost:8080/’ from origin ‘https://noghostsinside.com’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource…
If you remain calm when reading this error 😩, it is probably straightforward to understand that we cannot load resources requested from (origin) https://noghostsinside.com to http://localhost:8080/ because we are blocked by CORS.
This error also provides us with another piece of information, for solving our problem. What piece of information is that? The response is missing the Access-Control-Allow-Origin
header.
I decided to investigate further by navigating to my Network tab, and in the list of Names, I clicked where it said “localhost.” Checking in the Headers tab in the Request Headers section, I found the Origin header set to https://noghostsinside.com
but nothing about Access-Control-Allow-Origin
in the Response Headers.
Because we don’t have Access-Control-Allow-Origin
setup, as mentioned at the beginning of this post, our browser respects the Same-origin policy and doesn’t let us load resources from localhost. To overcome this obstacle we need to tell the server to allow access to resources provided by the `/` endpoint to our origin. Let’s proceed and do that.
How to configure CORS to your Express.js server
Remember that we have not set anything on the server side about CORS, right? Express.js suggests using a node package named cors
when dealing with CORS issues.
Let’s first install it (--save
flag is not needed anymore for saving dependencies)
npm install cors
Bashand change our code, based on the cors
‘s documentation, to
const express = require('express');
const cors = require('cors');
const app = express();
const PORT = 8080;
app.use(cors());
app.get('/', (req, res) => {
res.send({
name: 'No Ghosts Inside'
});
})
app.listen(PORT, () => {
console.log(`Your app is listening on port ${PORT}`);
})
JavaScriptSo we are just adding cors to be used by our application, right? Alright, but how can we validate it worked?
I returned to my browser and ran the fetch command I ran earlier. This time I got back a response!
{
"data": {
"name": "No Ghosts Inside"
}
}
That’s great! The CORS issue is solved, but it would be nice to know if something happened in the response’s headers, too, right?
By visiting the Network tab for localhost now, I saw indeed the Access-Control-Allow-Origin
header added in the response and an *
as its value. Having an * as its value implies that the browser can access a resource from any origin.
Defining explicit CORS origin
Great? I mean, yeah, we have solved the CORS issue, but do we want to give access to resources from all origins? No right? It’s best to clearly state what we want by using the cors
package to set a specific URL in the header. We can do this by changing our code to
const express = require('express');
const cors = require('cors');
const app = express();
const PORT = 8080;
app.use(cors({
origin: 'https://noghostsinside.com',
}));
app.get('/', (req, res) => {
res.send({
name: 'No Ghosts Inside'
});
})
app.listen(PORT, () => {
console.log(`Your app is listening on port ${PORT}`);
})
JavaScriptBy doing so, the header value will also change to Access-Control-Allow-Origin: https://noghostsinside.com
and we will now have explicitly allowed cross-origin resources access only to our blog. Well done! 😎 🥳