What is CORS?

In order to explain what (CORS) is, it is necessary to cover additional security mechanisms like Same Origin Policy. SOP restricts how an application or script loading from one origin (defined as domain, port or protocol) can interact with other origins. This mechanism is applied with the goal of reducing possible exploits like accessing data from other domains, and loading other malicious scripts to relay data. CORS is a another security mechanism that is defined in the Fetch Living Standard that utilizes HTTP-headers to define origins for each HTTP request to a server. This allows for Cross Origin Resource Sharing and added flexibility on top of the Same Origin Policy.

How CORS handle requests

CORS support a secure way to handle cross-origin requests and data transfer between browsers and servers. AJAX using XMLHttpRequests and the JavaScript Fetch API both rely on CORS. With the use of HTTP headers clients and servers can pass information and describe what origins are allowed to read/write information from a browser. CORS requests can be simple requests with allowed methods like GET, POST, or side-effect causing requests that require “pre-flight” approval.

Simple Requests

A simple request is one that uses the allowed methods: GET, HEAD, POST, and is restricted to certain headers (content-language, accept-language, etc) - these kind of requests do not trigger a pre-flight authorization check. Simple requests must meet all the following conditions:

Allowed Methods: GET, HEAD, POST
Allowed Headers: Accept, Accept-Language, Content-Language, Content-Type*
Allowed Content-Types: application/x-www-form-urlencoded, multipart/form-data, text/plain

Preflight Requests

Other requests that do not meet the above requirements (utilizing additional headers, etc) require use of the HTTP OPTIONS method to send additional information prior to the actual request. This OPTIONS stage asks for the Access-Control-Request-Method (defines the HTTP method the request will be making), and the Access-Control-Request-Headers that will define the headers the request will be sending.

The response headers returned from a preflight request will determine if the request can be processed. The Access-Control-Allow-Origin header can help the server define whether all origins can be included (as represented by the * wildcard), a specific origin, or even set to null. It is currently recommended not to return null due to possible serialization which may allow for origins with a “null” header.

Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: <origin>
Access-Control-Allow-Origin: null

Request Options in Fetch

The fetch API can accept a second parameter, an init object that controls everything from the HTTP methods, to header options, including cors policy.

Supplying Request Options

async function postData(url = '', data = {}) {
  // Default options are marked with *
  const response = await fetch(url, {
    method: 'POST', // *GET, POST, PUT, DELETE, etc.
    mode: 'cors', // no-cors, *cors, same-origin
    cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
    credentials: 'same-origin', // include, *same-origin, omit
    headers: {
      'Content-Type': 'application/json'
      // 'Content-Type': 'application/x-www-form-urlencoded',
    },
    redirect: 'follow', // manual, *follow, error
    referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
    body: JSON.stringify(data) // body data type must match "Content-Type" header
  });
  return response.json(); // parses JSON response into native JavaScript objects
}

postData('https://example.com/answer', { answer: 42 })
  .then(data => {
    console.log(data); // JSON data parsed by `data.json()` call
  });