CORS in plain simple language

Saurabh Tiwari
8 min readNov 11, 2020
No credits claimed for the image

If you are a web developer or have ever worked on any web technology concerning browsers and servers, chances are high that you are familiar with CORS. In my many years of web development, I have seen many developers concerned with the issues surrounding CORS.
In this article, I try to explain the concept of CORS in a plain simple words.

Disclaimer: This article deals with the concept of CORS from a very basic perspective and is written to provide a clear understanding of CORS grounds up. If you are an experienced web developer and already know about the concept of cross-origin sharing, this article might not be for you. However, you are always welcomed to provide your feedback.

CORS or Cross-Origin Resource Sharing is a policy to enable a secured and trusted transfer of data between a server (host) and a browser (client).

Let’s see how most of the data sharing happens in a browser. Almost all of the web applications you use in your browsers are backed by HTTP protocol. The web application code (usually written in JavaScript) initiates a HTTP Web request to a designated server. The server receives the request, the code at the server (usually written in languages like C#, Java etc.) processes the request and accordingly sends a response. The JavaScript code receives the response and makes it available to the user in one way or the other.

Sounds simple. May be not.

The key thing to understand here is that the browser is a tool that makes the network call on the behalf of your application. Your JavaScript code tells the browser the data of the call which includes the HTTP method, the body, the request parameters etc. The actual task of sending the request out to the network is with the browser and similarly when the server sends the response back the browser receives it first and then passes it to your JS code.

However, from security point of view things are not so simple. There are several forms of security attacks that might trick browser into sending a request different then the intended one. Similarly the response can be intercepted to perform things other than intended.

Same origin policy to rescue.

Same-origin policy is a web protocol that determines how a web page or script originating from one domain can interact with resources from other domain. As an implementation of this policy, web browsers do not allow web pages to interact with any domain other than their origin domain. For example: any web page originating from a domain ‘X’ is not allowed to connect to any resource on domain ‘Y’. Lets simplify this a little more:

When we access any website by hitting its URL on browser’s address bar, the browser locates the corresponding server and fetches the default page available there. Every website maintains a entry level default page to be served when the website is accessed. Usually this page is named index.html, but that is just a convention.

A lot happens between your hitting the URL and the browser showing you that first page. If you want to know how browsers work behind the scene, refer to this video that explains it in detail.

For example: When you hit https://google.com, you see a page with google doodle and a search bar. Consider this as the first page served from google.com. Now when you search anything from the google search box, a network call is sent and another page listing the search results is shown. As per the same-origin policy, if the first page originated from google.com, it can connect to a web resources available on google.com only. If for some reason, it wanted to connect to say facebook.com, the browser won’t allow it citing the same-origin policy restriction.

This arrangement worked fine for a long time when the web application used to work on the concept of server-side rendering. The same server used to host the application logic and based on the user input the same server used to serve the web pages to the browser. So the applications never really had to connect to resources on any other domain outside the host domain. This way the browser security policy worked well.

However, in modern era of web applications, a web application has to connect with a different domain other than the first domain for many reasons. One of the most common reason is that the server side rendering is not the de-facto rendering anymore. With the advent of web services and REST, it is now very common to host your application logic and web logic separately on different domains.

Consider this: Your website is hosted on a server X. This server only contains the static web pages, scripts and assets. The user hits your address on browser, the browser locates server X on the internet and gets the default page from server X. Since X only stores the static content when you perform any interaction on this page, the code has to connect with another server Y to fetch the data. The servers X and Y are usually known as web server and application server respectively.

But we know from our earlier understanding that the browsers won’t allow this because browsers respect same origin policy. Then how does this work? How almost every modern web application work. Now this is where the CORS or Cross origin resource sharing comes in picture.

The main idea behind same-origin policy was to prevent application code to interact with any untrusted resources. This is insecure both on the end of browsers as well as server because both might end up sharing data with untrusted domain. However, there can be cases (like above) where a web page might want to connect with multiple trusted resources different from the one originating the first page. In order to achieve this the CORS protocol was designed and in fact the CORS protocol is a mechanism by which the browser and server can identify themselves to each other by sharing various details before the actual transmission of data takes place. This helps in transfer of data between two different domain and at the same time retains the security.

That didn’t sound simple. Did it? Lets detail it further.

To achieve cross domain connection successfully a mechanism named CORS needs to be implemented and in fact implementing CORS is very straightforward. Its a mechanism that both your server and web code has to implement and execute mutually.

We know when a web page needs to fetch the data from server it makes a GET request with input parameters. When the web page needs to save some data to the server it makes a POST request with input body and so on. The CORS mechanism says that every network request to the server (GET, PUT, POST or DELETE) is preceded by an OPTIONS request, also called a PREFLIGHT request. OPTIONS is a HTTP supported VERB whose aim is to provide server with the incoming request’s domain. A body or parameter is not supplied along with the OPTIONS request rather the only form of data exchanged is in the form of Request headers in the request and Response headers by the server.

The basic premise of OPTIONS call is simple:
The OPTIONS request needs to specify its origin in the ‘origin’ header. Usually the browser automatically picks the current domain and sends it along with the request. For example: any request sent from google.com search page will have the https://google.com as the header as shown below.

Request headers originating from a search request on google.com

The server at its end has to keep a logic to check the ‘origin’ header in every incoming request. This way the server knows which domain has tried to connect to its resources. If the server trusts that domain the server can provide its consent by sending a response to the OPTIONS request containing the ‘Access-Control-Allow-Origin’ header. The server can choose to set either a wildcard (*) value or specify the name of a domain in this header. If the server sends *, it means that the server is OK to receive requests from any domain, the server doesn’t really care. This is usually the case with publicly open websites like google as shown below.

Response header received against a network request issued from google.com

If the server finds that the incoming domain is not a trusted domain, it can send an error response. In other cases, if the server is not open for public requests but finds that the incoming origin is a trusted origin it can send the response back by attaching the name of the origin in the ‘Access-Control-Allow-Origin’ as shown below.

Response headers received against a network request issued from gmail.com

In any case, the response to the OPTIONS request is parsed by the browser and if the browser finds that the server has given its consent i.e. either the server specifies a * or the name of the current domain (the same origin name as was sent in the request) only then the browser will make the actual call with data transmission else the browser will not allow any further communication with the server.

And that is the core idea behind the CORS or Cross-Origin-Resource-Sharing policy.

Although as the name indicates the main purpose of Cross-Origin-Resource-Sharing is to validate the data transfer between two different origins and we have already seen how that is achieved. But, the Access-Control-Allow-Origin is not the only headers available in the CORS mechanism. The server can specify various other details in the response to OPTIONS request that makes the identification of the resources more concrete and hence adds more to the security of data transmission. Two more headers that are commonly used are:

  1. Access-Control-Allow-Methods: The server uses this header to specify which kinds of HTTP requests does a resource allow. For example: Suppose, you initiated a PUT request from the browser. The browser made the preflight OPTIONS request and the server responded with the following headers.
Response header received against a network request issued by gmail.com

This header specify that the requested resource only allows GET, POST or OPTIONS request. The browser will parse the response and find that you were trying to make a PUT request but the resource doesn’t allow it. In this case, the browser will terminate your original PUT request and will send you a — 405 Method Not allowed error code.

2. Access-Control-Allow-Headers: This headers works pretty much the same as above header. The only difference being that the server uses this header to specify that which headers are allowed in the actual request.

There are many other headers available in the CORS mechanism which helps in verifying various other properties of the server resources before making the actual request. A detailed description of other available headers can be found here.

And with this, we have arrived at the end of this article and I hope you now have a good understanding of what CORS is and how does it work. Next time, you find your browser telling you that the request cannot be processed due to a CORS issue you know how to fix that.

In case you have any further questions regarding the topic or you find any thing missing, please feel welcomed to comment below and I will be happy to resolve them.

--

--

Saurabh Tiwari

Saurabh works as a full stack developer for a top IT MNC in India. Passionate about coding, he prefers working with frontend technologies and Node.Js.