You Must Carefully Configure CORS on Your Backend and This Will Get You Started
In this article, I introduce you to CORS or Cross-Origin-Resource-Sharing which is one of the most important and fundamental protocols used in web technology today. You will learn the basic concepts that you will use in the majority of cases you will ever encounter. In addition to that, we will see examples of how to correctly configure CORS in Node.js.

As human beings, we get the majority of the knowledge we have from others. Either by assisting to a lecture, by reading an article or a book, or by discussing a certain topic, we improve in a topic by getting in contact with people who know things we ignore. The same applies for web pages. It is uncommon to find a complex web page that gets all the data it displays from only one website or origin. Some of the resources displayed, like images, tweets and texts, come from other domains. This process of sharing resources between different origins is controlled by the protocol called CORS or Cross Origin Resource Sharing.
But why do we need an additional protocol for this type of Cross Origin Sharing, isn’t the traditional HTTP protocol enough?
In theory, the HTTP protocol is enough for Cross Origin Resource Sharing. In fact, when a page hosted on initial-website.com needs resources from another website cross-website.com , the page can simply send a GET or a POST request to cross-website.com to get the desired resource:
const xhr = new XMLHttpRequest();
const url = 'https://cross-website.com/resources/public-data/';
xhr.open('GET', url);
xhr.onreadystatechange = someHandler;
xhr.send();This is completely legit, and the handler can get the desired resource to be displayed on initial-website.com . However, this practice has huge security issues. It can allow ressources from malicious websites to be loaded in the current website that can contain your personal information such as your credit card number or your social security number. This permits the abnormal use of your APIs. To prevent this, CORS allows the developer to have control over what requests the server will respond to: request methods, headers and origins.
Why should you care?
When executing projects on a large scale with a big number of functionalities and routes, developers need to have control over which origins are allowed to send requests to their backend and what type of content these requests must have. Configuring CORS incorrectly can open the door for cross-origin exploits that compromise users’ personal information.
To fully understand how CORS can be used and configured, we will need to look at different requests from two points of view: client-side and server-side. From the client-side point of view, we will see which requests will trigger the CORS protocol and what will happen when CORS is triggered. From the server-side point of view, we will understand how we can configure CORS to enable or block certain requests using the example of a Node.js server. These two points of view are complementary. We start with the client which is going to send cross-origin requests to a server which already supports CORS.
Access Control Scenarios
We present three scenarios that demonstrate how Cross-Origin Resource Sharing works. All these examples use XMLHttpRequest, which can make cross-site requests in any supporting browser.
Simple requests
Some requests don’t trigger a CORS preflight. A CORS preflight resembles a handshake, it will be detailed in the next paragraph. Those are called “simple requests” in this article. A “simple request” is one that meets all the following conditions:
- One of the allowed methods:
GET,HeadorPOST - Headers allowed (Apart from the headers automatically set by the user agent (for example,
Connection,User-Agent):Accept,Accept-Language,Content-Language,Content-Type(under some conditions, see below) - The only allowed values for the
Content-Typeheader are:application/x-www-form-urlencoded,multipart/form-data,text/plain
For example, suppose web content at https://foo.example wishes to invoke content on domain https://bar.other. Code of this sort might be used in JavaScript deployed on foo.example:
const xhr = new XMLHttpRequest();
const url = 'https://bar.other/resources/public-data/';
xhr.open('GET', url);
xhr.onreadystatechange = someHandler;
xhr.send();Because this request meets all of the previous conditions, preflight will not be triggered and CORS will handle this request in this very simple way:

Once the simple request is received from the client, the server responds normally with the resource requested. The server also adds a header to the response Access-Control-Allow-Origin: * which means that the resource sent by the server to the client can be accessed from any origin. If the resource requested from the client is restricted to the origin foo.example for example, the header added by the server would be Access-Control-Allow-Origin: foo.example. Therefore, any client requesting this resource from an origin different from foo.example won’t be able to access the response.
Preflighted requests
Unlike simple requests discussed above, for “preflighted” requests the browser first sends an HTTP request using the OPTIONS method to the resource on the other origin, in order to determine if the actual request is safe to send. Any request that does not satisfy the conditions of a ‘simple request’ is preflighted. Cross-site requests are preflighted since they may have implications to user data.
The following is an example of a request that will be preflighted:
const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://bar.other/resources/post-here/');
xhr.setRequestHeader('X-PINGOTHER', 'pingpong');
xhr.setRequestHeader('Content-Type', 'application/xml');
xhr.onreadystatechange = handler;
xhr.send('<person><name>Arun</name></person>');In the above request, two conditions do not match the conditions for simple requests. The first one is using an “exotic” header X-PINGOTHER and the second one is using an xml body Content-Type: application/xml .

The client will first send a preflight request to the server using the OPTION method asking for permission to use :
- a
POSTmethod in theAccess-Control-Request-Header: POSTheader X-PINGOTHERandContent-Typeheaders in theAccess-Control-Request-Header: X-PINGOTHER, Content-Typeheaders
The server will respond with the allowed origin, methods and headers, and thus granting permission to the client to send the MAIN request, with the specified Origin, Headers and Content-Type.
There is one more interesting point to note, the server allowed the client to access the resource for a max duration of 86400 seconds as you can see in the preflight response using the header Access-Control-Max-Age: 86400 . This means that in the next 24 hours, the client can request the same resource without asking for permission again.
Requests with Credentials
The most interesting capability exposed by CORS is the ability to make "credentialed" requests that are aware of cookies and HTTP Authentication information. By default, in cross-site XMLHttpRequest, browsers will not send credentials. A specific flag has to be set on the XMLHttpRequest object constructor when it is invoked.
In this example, content originally loaded from http://foo.example makes a simple GET request to a resource on http://bar.other which sets Cookies. Content on foo.example might contain JavaScript like this:
const invocation = new XMLHttpRequest();
const url = 'http://bar.other/resources/credentialed-content/';
function callOtherDomain() {
if (invocation) {
invocation.open('GET', url, true);
invocation.withCredentials = true;
invocation.onreadystatechange = handler;
invocation.send();
}
}Line 7 shows the flag on XMLHttpRequest that has to be set in order to make the invocation with Cookies, namely the withCredentials boolean value. By default, the invocation is made without Cookies.

The client sent the request with a cookie in the headers. The server confirms to the client that credentials are allowed in the server configuration using the header Access-Control-Allow-Credentials: true . Since this is a simple GET request, it is not preflighted, but the browser will reject any response that does not have the Access-Control-Allow-Credentials: true header, and not make the response available to the invoking web content.
Configuring the CORS protocol in your Node.js backend
CORS configuration is very flexible. You can allow Cross-Origin-Resource-Sharing for all the routes of your Node.js app or exclusively for specific ones. You can as well configure CORS options differently for every root. Moreover, you can update CORS options dynamically by getting the allowed Origins from a database for example.






