What is Cross-Origin Resource Sharing (CORS)?
Cross-Origin Resource Sharing (CORS) is a protocol that enables scripts running on a browser client to interact with resources from a different origin. This is useful because thanks to the same-origin policy followed by
CORS — Why Is It Needed?
The same-origin policy fights one of the most common cyber-attacks out there: Cross-Site Request Forgery CSRF). In this maneuver, a malicious website attempts to take advantage of the browser’s cookie storage system.
- a different scheme (HTTP or HTTPS)
- a different domain
- a different subdomain
- a different port
Long back, sharing resources from https://ayushv.medium.com with a different domain (google.com/api/getdata), different subdomain
(api.ayushv.medium.com), different port (ayushv.medium.com:5050), different protocols (http://ayushv.medium.com) were not allowed. After CORS became a standard, browsers do allow all these.
However, there are legitimate scenarios where cross-origin access is desirable or even necessary. For example, if you’re running a React SPA that makes calls to an API backend running on a different domain. Web fonts also rely on CORS to work. CORS introduces a standard mechanism that can be used by all browsers for implementing cross-domain requests. The spec defines a set of headers that allow the browser and server to communicate about which requests are (and are not) allowed. CORS continues the spirit of the open web by bringing API access to all.
Identifying a CORS Response
When a server has been configured correctly to allow cross-origin resource sharing, some special headers will be included. Their presence can be used to determine that a request supports CORS. Web browsers can use these headers to determine whether or not an
XMLHttpRequest call should continue or fail.
There are a few headers that can be set, but the primary one that determines who can access a resource is
Access-Control-Allow-Origin. This header specifies which origins can access the resource. For example, to allow access from any origin, you can set this header as follows:
Or it can be narrowed down to a specific origin:
Understanding CORS Request Types
There are two types of CORS requests: “simple” requests, and “preflight” requests, and it’s the browser that determines which is used. As the developer, you don’t normally need to care about this when you are constructing requests to be sent to a server. However, you may see the different types of requests appear in your network log and, since it may have a performance impact on your application, it may benefit you to know why and when these requests are sent.
Let’s have a look at what that means in more detail in the next couple of sections.
Simple requests (GET, POST, and HEAD)
The browser deems the request to be a “simple” request when the request itself meets a certain set of requirements:
- One of these methods is used:
- A CORS safe-listed header is used (
Accept, Accept-Language and Content-Language)
- When using the
Content-Typeheader, only the following values are allowed:
- No event listeners are registered on any
ReadableStreamobject is used in the request
The request is allowed to continue as normal if it meets these criteria and the
Access-Control-Allow-Origin header is checked when the response is returned.
Preflight requests (OPTIONS)
If a request does not meet the criteria for a simple request, the browser will instead make an automatic preflight request using the
OPTIONS method. This preflight request is made by some browsers as a safety measure to ensure that the request being done is trusted by the server. Meaning the server understands that the method, origin, and headers being sent on the request are safe to act upon.
This call is used to determine the exact CORS capabilities of the server, which is in turn used to determine whether or not the intended CORS protocol is understood. If the result of the
OPTIONS call dictates that the request cannot be made, the actual request to the server will not be executed.
The preflight request sets the mode as
OPTIONS and sets a couple of headers to describe the actual request that is to follow:
Access-Control-Request-Method: The intended method of the request (e.g.,
Access-Control-Request-Headers: An indication of the custom headers that will be sent with the request
Origin: The usual origin header that contains the script's current origin
An example of such a request might look like this:
curl -i -X OPTIONS localhost:3001/api/ping \
-H 'Access-Control-Request-Method: GET' \
-H 'Access-Control-Request-Headers: Content-Type, Accept' \
-H 'Origin: http://localhost:3000'
This request basically says “I would like to make a GET request with the
Accept headers from http://localhost:3000 - is that possible?".
The server will include some
Access-Control-* headers within the response to indicate whether the request that follows will be allowed or not. These include:
Access-Control-Allow-Origin: The origin that is allowed to make the request, or
*if a request can be made from any origin
Access-Control-Allow-Methods: A comma-separated list of HTTP methods that are allowed
Access-Control-Allow-Headers: A comma-separated list of the custom headers that are allowed to be sent. If you use custom headers (eg.
x-authentication-tokenyou need to return it in this ACA header response to
OPTIONScall otherwise, the request will be blocked.
Access-Control-Expose-Headers: Similarly, this response should contain a list of headers that will be present in the actual response to the call and should be made available to the client. All other headers will be restricted.
Access-Control-Allow-Credentials: This header is only required to be present in the response if your server supports authentication via cookies. The only valid value for this case is
Access-Control-Max-Age: The maximum duration that the response to the preflight request can be cached before another call is made
The response would then be examined by the browser to decide whether to continue with the request or to abandon it.
So a response to the earlier example might look like this:
HTTP/1.1 204 No Content
Access-Control-Allow-Headers: Content-Type, Accept
Date: Fri, 05 Apr 2019 11:41:08 GMT
Access-Control-Allow-Origin header, in this case, allows the request to be made from any origin, while the
Access-Control-Allow-Methods header describes only the accepted HTTP methods. If a given HTTP method is not accepted, it will not appear in this list.
In this example,
Access-Control-Allow-Headers echos back the headers that were asked for in the
OPTIONS request. This indicates that all the requested headers are allowed to be sent. If for example, the server doesn't allow the
Accept header, then that header would be omitted from the response and the browser would reject the call.
Handling CORS Error
The best way is to follow CORS standards and define a set of headers that allow the browser and server to communicate about which requests are (and are not) allowed. This is the best-case scenario — you should be able to implement the proper CORS response on the server which you’re calling. If the API is using
express for node you can use the simple
cors package. If you want to make your site properly secure, consider using a whitelist for the
For local development, there are some hacks:
- Plugins for chrome by which browser bypasses all CORS filters.
Allow CORS: Access-Control-Allow-Origin
Easily add (Access-Control-Allow-Origin: *) rule to the response header.
Moesif Origin & CORS Changer
This plugin allows you to send cross-domain requests. You can also override Request Origin and CORS headers.
- One more way is to start chrome with a flag of disable-web-security. That particular web session will be without CORS. This is actually bypassing the web security that chrome has.
chrome --disable-web-security --user-data-dir
More about CORS
If you wish to learn more about CORS details I recommend checking out the detailed MDN article.
I hope you have found this useful. Thank you for reading :)