DEV Community

Bilal Ul Haque
Bilal Ul Haque

Posted on

Cross-Origin Resource Sharing (CORS)

CORS main image

Consider the following scenario: You attempt to use your website’s GET() endpoint to retrieve some data from an API, but an error results.

The Access-Control-Allow-Origin header has a value of “some URL” that is not equal to the supplied origin,” or “The Access-Control-Allow-Origin header has a value of “No Access-Control-Allow-Origin header is present on the requested resource,” written in red text, indicating that your request was denied due to CORS policy.

Client server communication

What is CORS?

CORS (Cross-Origin Resource Sharing) is a method that permits resources to be loaded from one origin to another while preserving the security and integrity of the website. Popular web browsers like Chrome and Mozilla Firefox use this security technique to determine which cross-site requests are secure.

Modern browsers use the same-origin policy to limit access from scripts to resources outside their domain for security concerns. This policy was created in reaction to malicious activities including cross-site request forgery (CSRF) assaults and theft of personal information from other web servers.

Why does the same origin exist?

You might use cookies, like many websites, to remember login information or session details. When they are created, those cookies are restricted to a specific domain. The browser will include the cookies made specifically for that domain with each HTTP request to that domain. This occurs on every HTTP request, whether those for AJAX, HTML sites, or static images.

This indicates that a cookie is stored for https://exampleapi.com when you log into https:// exampleapi.com. The bank may have developed a REST API at https:// exampleapi.com/api if it is a single-page React application so that the SPA can interface with it using AJAX.

Unfortunately, developers that want to fetch different resources from various origins found this same-origin constraint to be somewhat restrictive. The CORS HTTP protocol was created to inform browsers to allow restricted resources on a web page to be requested from other domains in order to loosen restrictions a little. Here is an example of a case where information could be requested from an external source, such as an API (this is a very standard practice for client-side JavaScript code):

  • Using CORS headers, the resource origin sends a preflight request to the external web server.

  • The preflight request is then validated by the external web server to ensure that scripts are authorized to make the request.

  • The external web server replies with its own set of HTTP headers that specify the allowed request methods, origins, and custom headers after the request has been confirmed. Information on whether it is appropriate to pass along credentials, such as authentication headers, may also be included in this final server response.

Why do we need CORS?

A script that runs in a user’s browser would typically only ever need to access resources from the same origin (think about API calls to the same backend that served the JavaScript code in the first place). Therefore, it is good for security that JavaScript typically cannot access resources on other origins.

“Other origins” here refers to the fact that the URL being viewed is different from the location where the JavaScript is being executed by having:

  • A different scheme (HTTP or HTTPS)

  • An alternative domain or port

Cross-origin access, however, may be required or even desired in certain situations. As in the case of a React SPA that communicates with an API backend that is hosted on a different domain.

As you can see, CORS is an important protocol for making cross-domain requests possible, in cases where there’s legitimate need.

How does CORS work?

CORS requests come in two types: simple requests and preflighted requests. The criteria for determining if a request is preflighted are discussed later:

Simple requests:

  • A CORS request that doesn’t need to go through any preflight requests (initial checks) is referred to as a simple request.
  • AJAX request is started by a browser tab that is open to https://www.mydomain.com. GET widgets at https://api.mydomain.com
  • The browser automatically inserts the Origin Request Header along with headers like Host for cross-origin requests
  • The Origin request header is examined by the server. The Access-Control-Allow-Origin is set to the value in the request header Origin if the Origin value is allowed.
  • The Access-Control-Allow-Origin header is checked by the browser to verify if it matches the origin of the tab when it receives the answer. If not, the reply is suppressed. If the Access-Control-Allow-Origin either contains the wildcard * operator or exactly matches the single origin, the check succeeds, as in this example.

Preflight requests:
The other kind of CORS request is a preflight. A preflight request is a CORS request in which the browser must first make a preflight request (also known as a preliminary probe) to the server to determine whether the original CORS request can be processed. It is an additional HTTP request using the OPTIONS method. The browser performs this for every unsafe request that is intended to alter data — for example, POST, PUT, or DELETE requests.

We refer to the original CORS request as preflighted because it was preceded by a preflight request.

Common circumstances necessitating preflighted requests:

The Content-Type header for a website’s AJAX call to POST JSON data to a REST API is application/json.

  1. A website makes an AJAX call to an API and includes a token in the request header to authenticate the API. Authorization
  2. This means that a REST API frequently has the bulk of AJAX requests preflighted when it powers a single-page application.

Process communication

Simple requests vs. pre-flighted requests:
Simple requests are defined as those that do not result in a CORS preflight. However, after the request has been determined to be a basic request, some requirements must be met. These circumstances are:

  • The request’s HTTP method needs to be one of the following: head, Post, or Get
  • Except for the headers that are automatically set by the user agent, the request headers should only contain CORS safe-listed headers like Accept, Accept-Language, Content-Language, and Content-Type.
  • Only one of these three values, total, should be present in the Content-Type header: Multipart/form-data, application/x-www-form-URLencoded, or text/plain
  • The XMLHttpRequest returned object has no registered event listeners.
  • XMLHttpRequest must use the upload attribute.
  • There shouldn’t be any Readable Stream objects in the request.

The request is regarded as a pre-flighted request if either of these requirements is not met. For these requests, the browser must first submit an OPTIONS method request to the alternative origin.

This is used to determine whether the actual request can be sent to the server without risk. The response headers to the pre-flighted request determine whether the real request is approved or denied. The request is not sent if the main request’s headers and these response headers conflict.

Enabling CORS:
Suppose we faced the CORS error. There are many ways we could solve this issues depending on our access to the server on which the resources are hosted. There are two ways:

  • Access to the backend server
  • Access to only the frontend

Access to the backend:
You may set up the server to respond with the proper headers to enable resource sharing across various origins because CORS is essentially an HTTP header-based method. Look at the CORS headers we covered previously, and adjust the headers as necessary.

For example in node.js+express.js application:

backend 1

The default configuration will be applied if a CORS configuration object is not given, which is identical to:

backend 2

The following describes how to set up CORS on your server such that it will only accept GET requests from https://example.com with the headers Content-Type and Authorization and a preflight cache time of 10 minutes:

backend 3

Access to the front end:
If you don’t have access to the backend server like a public API. Due to this, you cannot add headers to the response received. So in that case you could use a proxy server that’ll add the CORS headers to the proxied request. The proxy server is available at https://cors-anywhere.herokuapp.com/. You can also build your own proxy server.

Instead of directly making the request to the server, simply append the proxy server’s URL to the start of the API’s URL.

frontend 1

Common Pitfalls:

  1. Using the Access-Control-Allow-Origin (all) operator:
    The same-origin criterion is overridden by CORS in order to ensure security. While utilising *, the majority of CORS’ security rules are disabled. Wildcard is permissible in some circumstances, such as with an open API that is integrated into various websites hosted by third parties. The security may be enhanced by giving the API its own domain. For instance, your open API https://api.example.com may respond with Access-Control-Allow-Origin while your main website’s API https://www.example.com/api may still respond with Access-Control-Allow-Origin: https://www.example.com.

  2. Multiple domains are returned for the Access-Control-Allow-Origin header:
    Unfortunately, the standard does not allow the Access-Control-Allow-Origin: https:// example.com, https://www.example.com. Although the server can only return one domain or *, the Origin request header can be used.

  3. Choosing a wildcard, such as *.example.com:
    This is not covered by the CORS specification because wildcard can only be used to imply that all domains are permitted.

  4. Not including non-standard or protocol ports:
    Access-Control-Allow-Origin: example.com is invalid since the protocol is absent.
    Similar to this, you will encounter problems with Access-Control-Allow-Origin: localhost unless the server is actually running on a normal HTTP port like: 80.

  5. Ignoring the Origin header in the Vary response:
    Most CORS frameworks do this automatically, but you still need to let clients know that server responses differ based on where the request came from.

  6. Failure to define Access-Control-Expose-Headers:
    If a required header is absent, the CORS request will still be successful, but any response headers that are not whitelisted will be obscured in the browser tab. The following common response headers are always made available for CORS requests:
    Cache-Control, Content-Type, Language, Expires, and Last-Modified

  7. When Access-Control-Allow-Credentials is set to true, using a wildcard:
    Many people become entangled in this complex subject. The wildcard operator cannot be used on any of the response headers, including Access-Control-Allow-Origin, if the response includes Access-Control-Allow-Credentials: true.

Top comments (7)

Collapse
 
jaironlanda profile image
Jairon Landa

Awesome!

Great article, very detailed.

Collapse
 
bilalulhaque profile image
Bilal Ul Haque

Thank you.
Stay up-to-date with the latest technological advancements by following me.

Collapse
 
glszabolcs6 profile image
Gál Szabolcs #Luckylukee @GlSzabolcs6

thank you! Perfect

Collapse
 
bilalulhaque profile image
Bilal Ul Haque

Thanks @glszabolcs6
Stay up-to-date with the latest technological advancements by following me.

Collapse
 
glszabolcs6 profile image
Gál Szabolcs #Luckylukee @GlSzabolcs6

Thank you🙏

Collapse
 
__junaidshah profile image
Junaid

Great article , @bilalulhaque

Collapse
 
bilalulhaque profile image
Bilal Ul Haque

Thank you brother, Means a lot.