Cross-Origin Resource Sharing (CORS)

Image for post
Image for post

📄 Table of Contents

  • why CORS error occur
  • same origin policy

▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬ ✦ ✦ ✦ ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬

Why was the CORS error there in the first place?

The error stems from a security mechanism that browsers implement called the same-origin policy.

The same-origin policy fights one of the most common cyber attacks out there: cross-site request forgery. In this maneuver, a malicious website attempts to take advantage of the browser’s cookie storage system.

For every HTTP request to a domain, the browser attaches any HTTP cookies associated with that domain. This is especially useful for authentication, and setting sessions. For instance, it’s feasible that you would sign into a web app like facebook-clone.com. In this case, your browser would store a relevant session cookie for the facebook-clone.com domain:

Image for post
Image for post

And this is great! The session cookie gets stored. And every time you re-visit the facebook-clone.com tab, and click around the app, you don’t have to sign in again. Instead, the API will recognize the stored session cookie upon further HTTP requests.

The only trouble is that the browser automatically includes any relevant cookies stored for a domain when another request is made to that exact domain. Therefore, a scenario like this can happen. Say you clicked on a particularly trick popup add, opening evil-site.com.

Image for post
Image for post

The evil site also has the ability send a request to facebook-clone.com/api. Since the request is going to the facebook-clone.com domain, the browser includes the relevant cookies. Evil-site sends the session cookie, and gains authenticated access to facebook-clone. Your account has been successfully hacked with a cross-site request forgery attack.

Luckily, in this situation, like a hawk ready to strike, the browser will step in and prevent the malicious code from making an API request like this. It will stop evil-site and say “Blocked by the same-origin policy. 🕶️”

How does the same-origin policy work under the hood?

Under the hood, the browser checks if the origins of the web application and the server match. Above, the origins were simplified to the frontend application and backend server domains. But really, the origin is the combination of the protocol, host, and port. For example, in https://www,facebook-clone.com, the protocol is https://, the host is www.facebook-clone.com, and the hidden port number is 443 (the port number typically used for https).

To conduct the same-origin check, the browser accompanies all requests with a special request that sends the domain information receiving server. For example, for an app running on localhost:3000, the special request format looks like this:

Origin: http://localhost:3000

Reacting to this special request, the server sends back a response header. This header contains an Access-Control-Allow-Origin key, to specify which origins can access the server’s resources. The key will have one of two values:

One: the server can be really strict, and specify that only one origin can access it:

Access-Control-Allow-Origin: http://localhost:3000

Two: the server can let the gates go wide open, and specify the wildcard value to allow all domains to access its resources:

Access-Control-Allow-Origin: *

Once the browser receives this header information back, it compares the frontend domain with the Access-Control-Allow-Origin value from the server. If the frontend domain does not match the value, the browser raises the red flag and blocks the API request with the CORS policy error.

▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬ Next ▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬

Q. What if you wanted to get weather data from another country?

Doing that may sometime throw below error:

request has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

In other words, there are public resources that should be available for anyone to read, but the same-origin policy blocks that. Developers have used work-arounds such as JSONP, but Cross-Origin Resource Sharing (CORS) fixes this in a standard way.

Enabling CORS lets the server tell the browser it’s permitted to use an additional origin.

How does CORS work? #

Remember, the same-origin policy tells the browser to block cross-origin requests. When you want to get a public resource from a different origin, the resource-providing server needs to tell the browser “This origin where the request is coming from can access my resource”. The browser remembers that and allows cross-origin resource sharing.

Step 1: client (browser) request #

When the browser is making a cross-origin request, the browser adds an Origin header with the current origin (scheme, host, and port).

Step 2: server response #

On the server side, when a server sees this header, and wants to allow access, it needs to add an Access-Control-Allow-Origin header to the response specifying the requesting origin (or * to allow any origin.)

Step 3: browser receives response #

When the browser sees this response with an appropriate Access-Control-Allow-Origin header, the browser allows the response data to be shared with the client site.

Preflight requests for complex HTTP calls #

If a web app needs a complex HTTP request, the browser adds a preflight request to the front of the request chain.

The CORS specification defines a complex request as

  • A request that uses methods other than GET, POST, or HEAD
  • A request that includes headers other than Accept, Accept-Language or Content-Language
  • A request that has a Content-Type header other than application/x-www-form-urlencoded, multipart/form-data, or text/plain

Browsers create a preflight request if it is needed. It’s an OPTIONS request like below and is sent before the actual request message.

OPTIONS /data HTTP/1.1
Origin: https://example.com
Access-Control-Request-Method: DELETE

On the server side, an application needs to respond to the preflight request with information about the methods the application accepts from this origin.

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, DELETE, HEAD, OPTIONS

The server response can also include an Access-Control-Max-Age header to specify the duration (in seconds) to cache preflight results so the client does not need to make a preflight request every time it sends a complex request.

REST Design — Choosing the Right HTTP Method

One of the challenges when designing a REST API is choosing the right HTTP method (GET, PUT, POST etc.) that corresponds with the operation being performed. Some people incorrectly assume that they can freely choose any method as long as the client and the server agree on it. This is wrong because a request passes through many intermediaries and middleware applications which perform optimizations based on the HTTP method type. These optimizations depend on two key characteristics of HTTP methods: idempotency and safety, which are defined in the HTTP specification.

Safe HTTP Methods: Safe methods aren’t expected to cause any side effects. These operations are read-only. E.g. querying a database.

Idempotent HTTP Methods: Idempotent methods guarantee that repeating a request has the same effect as making the request once.

Idempotency and safety are properties of HTTP methods that server applications must correctly implement.

GET: Idempotent & Safe

GET requests are used for retrieving information. These requests must be idempotent and safe: any operation invoked using GET must not alter the state of any resource.

GET /books

To get a specific book,

GET /books/<title>

For more read @

Experience with Front-end Technologies and MERN / MEAN Stack. Working on all Major UI Frameworks like React, Angular.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store