What is CORS (Cross-Origin Resource Sharing)?

Nov 24, 2020 - 12 min read
Ryan Thelin
editor-page-cover

Modern web pages use more outside scripts and assets than ever before. By default, JavaScript follows the same-origin policy and can only make calls to URLs on the same domain as the running script. So, how can we get our JavaScript-powered pages to use outside scripts?

CORS is the answer.

Cross-origin resource sharing (CORS) is a mechanism that allows a way for web pages to access API or assets running on a different restricted domain.

Today, we’ll explore CORS in-depth and learn how to activate it on different front-end frameworks.

Here’s what we’ll cover today:



Expand your front-end skillset

Become a front-end developer in half the time, without scrubbing through tutorial videos.

Become a Front End Developer



What is CORS?

Cross-origin resource sharing (CORS) is a browser mechanism that allows a web page to use assets and data from other pages or domains.

Most sites need to use resources and images to run their scripts. These embedded assets present a security risk as the assets could contain viruses or allow server access to a hacker.

Security policies mitigate the security risks of asset use. The policy rules what assets a requesting site can load based on origin or contents and regulates the amount of access given to the requesting site. Each policy must have enough restrictions to secure the web server but not enough to hurt functionality.

Same-origin is the most secure type of policy that prevents access to any outside server. All assets for a site must come from the same origin. Most of the time, same-origin is a good choice as most scripts can function with only local resources. However, sometimes we’ll want to allow access to outside assets such as videos, live-streams, or pictures.

What is an origin?

Origin refers to 3 parts: a protocol, a host, and port number. Protocol refers to the application layer protocol, often HTTP. The host is the main site domain that all pages fall under, like Educative.io. Finally, the port number is the communication endpoint for the request, which defaults to port 80.

Many sites use a form of cross-origin policy called cross-origin resource sharing (CORS) that defines a way for a web page and the host server to interact and determine if it is safe for the server to allow access to the web page.

CORS is a middle ground policy between security and functionality as the server can approve certain outside requests without the insecurity of approving all requests.


Lived Example of CORS

The most prevalent example of CORS are advertisements on non-native sites.

For example, imagine you’re watching a YouTube video and you see an Android advertisement. YouTube’s servers are reserved for their essential resources and cannot locally store every possible advertisement.

Instead, all ads are stored on the advertisement company’s servers. The advertisement company has allowed viewing access to YouTube to allow a YouTube web page to play the stored Android advertisement video.

The benefit of this system is that YouTube can use content from another server without using local storage. Also, it allows the advertisement company to roll out new advertisements quickly as they only need to update what ad is passed to YouTube from their server.


What assets can CORS request?

Sites use CORS requests to load:

  • Fetch requests or HTTP requests likeXMLHTTPRequests
  • Web-fonts and TrueType fonts only available for cross-site loading
  • Web GL textures
  • Images and videos
  • CSS shapes

You can use CORS to freely embed these types of assets in your site and avoid the creation of local copies.

Enjoying the article? Scroll down to sign up for our free, bi-monthly newsletter.


How does CORS work?

CORS adds new HTTP headers to the list of standard headers. The new CORS headers allow the local server to keep a list of allowed origins.

Any requests from these origins are granted and they’re permitted to use restricted assets. The header to add to the acceptable origins list is Access-Control-Allow-Origin.

There are many different types of response headers that enable different levels of access. Here are a few more examples of CORS HTTP headers:

  • Access-Control-Allow-Credentials
  • Access-Control-Allow-Headers
  • Access-Control-Allow-Methods
  • Access-Control-Expose-Headers
  • Access-Control-Max-Age
  • Access-Control-Request-Headers
  • Access-Control-Request-Method
  • Origin

When a web browser wants to access a site, it will send the site server a CORS GET request. If granted, the GET request will allow the browser to view the page, but nothing more.

Most servers allow GET requests from any origin but will block other types of requests.

svg viewer
GET request in action

The server will either send back the wildcard value, *, which means access to the requested data is unrestricted, or the server will check the list of allowed origins.

If the requester’s origin is on the list, the web page is permitted to view the web page and the server echoes the name of the allowed origin.

If not, the server will return a declined message that states if the origin is disallowed from all access or if it is disallowed from the specific action.


Types of CORS requests

​ The GET request above is the simplest form of request to allow viewing only. There are different types of requests that allow for more complex behavior like cross-origin requests for data manipulation or deletion.

These different requests exist because we may want to grant different levels of access depending on the origin. Perhaps we’d like all GET requests to be granted but only our partnered advertising company can edit assets.

The separation of request types allows us to decide the exact clearance level of an origin and ensure each origin can only perform requests essential to its function.

Most requests fall into two major categories:

  • Simple requests: These requests do not trigger a preflight check and use only “safelisted” CORS headers.
  • Preflight requests: These requests send a “preflight” message that outlines what the requester would like to do before the original request. The requested server reviews this preflight message to ensure the request is safe to allow.

Simple requests

Simple requests do not require a preflight check and use one of three methods: GET, POST, and HEAD. These requests are from before CORS was invented and therefore are allowed to skip to CORS preflight check.


GET

The GET request asks to view a representation of the shared data file from a specific URL. It can also be used to trigger file downloads.

An example would be visiting any site on the web. As an outside user, we can only see the content of the site and cannot alter the text or visual elements.

GET /index.html

HEAD

The HEAD request previews the headers that would be sent with a GET request. It’s used to sample what content exists at a specific URL without accessing it.

For example, you could HEAD a download URL to receive its Content-Length header. This would let you know the file size of the download before you agree to download it.

HEAD /index.html

POST

The POST request asks to transmit data to the requested server, which could result in a change in the server. If a POST request is triggered multiple times, it may have unexpected behavior.

An example of this is adding a comment to a forum thread.

The browser sends a request to add your input comment to the server. Once accepted, the forum server takes the newly received data (the comment) and stores it for others to view.

POST /test HTTP/1.1
Host: foo.example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 27
field1=value1&field2=value2

Keep learning about front-end development.

Learn the front-end skills employers are looking for. Educative’s Paths give you access to all the best front-end lessons and hands-on examples from across our course library.

Become a Front End Developer


Preflight requests

Some methods generate an additional preflight request that is sent ahead of the original request. Preflight requests are automatically generated with the OPTIONS method for functions that can affect user data or make a grand change in the server.

The OPTIONS method is used to gather further information on how the requester is permitted to interact with the server. It returns what method options the requester is approved for.

OPTIONS is a safe method, meaning it cannot change anything accessed. out as it’ll be sent behind the scenes if you use a preflight method.

You’ll not need to manually call the OPTIONS method. Preflight requests are automatically issued from the browser when you attempt to request a method tagged as “to be preflighted”.

The most common preflighted method is DELETE that deletes the selected file or asset from the server.

svg viewer
Background process of a preflight request

The preflight request includes the requester’s origin and the desired method, indicated using Access-Control-Request-Method. The server analyzes the preflight request to check if this origin has access to do such a method.

If yes, the server returns all methods the origin is permitted to use and indicates that you can send the original request.

If not, the original request is ignored.

The requester browser can then cache this preflight approval for as long as it is valid.

You can see the expiration date of the approval by checking the value of Access-Control-Max-Age.

The requester browser can then cache this preflight approval for as long as it is valid. You can see the expiration date of the approval by checking the value of Access-Control-Max-Age.


Quick Guide to implement CORS

​ To get started with CORS, you’ll have to enable it on your apps. Below is a selection of code from different frameworks that will make your app CORS ready.


Nodejs Express App

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "YOUR-DOMAIN.TLD"); // update to match the domain you will make the request from
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});
app.get('/', function(req, res, next) {
  // Handle the get for this route
});
app.post('/', function(req, res, next) {
 // Handle the post for this route
});

Flask

Install the package:

$ pip install -U flask-cors

Then add it to your Flask app:

# app.py
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
cors = CORS(app)

Apache

Add the following line inside either <Directory>, <Location>, <Files> or <VirtualHost> sections of your server config.

Header set Access-Control-Allow-Origin "*"

To ensure changes are applied correctly, run apachectl -t then reload your Apache using sudo service apache2 reload.


Spring Boot Applications in Kotlin

The following Kotlin code block enables CORS on Spring Boot applications.

import org.springframework.http.HttpMethod
import org.springframework.http.HttpStatus
import org.springframework.stereotype.Component
import org.springframework.web.server.ServerWebExchange
import org.springframework.web.server.WebFilter
import org.springframework.web.server.WebFilterChain
import reactor.core.publisher.Mono
@Component
class CorsFilter : WebFilter {
    override fun filter(ctx: ServerWebExchange?, chain: WebFilterChain?): Mono<Void> {
        if (ctx != null) {
            ctx.response.headers.add("Access-Control-Allow-Origin", "*")
            ctx.response.headers.add("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS")
            ctx.response.headers.add("Access-Control-Allow-Headers", "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range")
            if (ctx.request.method == HttpMethod.OPTIONS) {
                ctx.response.headers.add("Access-Control-Max-Age", "1728000")
                ctx.response.statusCode = HttpStatus.NO_CONTENT
                return Mono.empty()
            } else {
                ctx.response.headers.add("Access-Control-Expose-Headers", "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range")
                return chain?.filter(ctx) ?: Mono.empty()
            }
        } else {
            return chain?.filter(ctx) ?: Mono.empty()
        }
    }
}

Nginx

The following code block enables CORS with preflight request support.

#
# Wide-open CORS config for nginx
#
location / {
     if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        #
        # Custom headers and headers various browsers *should* be OK with but aren't
        #
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        #
        # Tell the client that this pre-flight info is valid for 20 days
        #
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain; charset=utf-8';
        add_header 'Content-Length' 0;
        return 204;
     }
     if ($request_method = 'POST') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
     }
     if ($request_method = 'GET') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
     }
}

What to learn next

Congratulations on finishing your first steps toward CORS mastery. This powerful front-end tool is essential to be hired by top web development employers like Google and Amazon.

To continue your CORS learning journey, some next topics to check out are:

  • Request authentication with credentials
  • Ajax requests with CORS
  • CORS in PHP
  • Third-party cookies in CORS

To continue to widen your front-end skill-set, Educative has created the Become a Front End Developer Path. This path includes tutorials and in-browser examples on writing and styling website front-ends. By the end, you’ll have practiced several real-world projects and even launch your own personal website.

Happy learning!


Continue learning about front-end JavaScript


WRITTEN BYRyan Thelin

Join a community of 500,000 monthly readers. A free, bi-monthly email with a roundup of Educative's top articles and coding tips.