Mariko Kosaka [X](https://twitter.com/kosamari)

<br />


Published: November 5, 2018

<br />

The browser's same-origin policy blocks reading a resource from a different
origin. This mechanism stops malicious sites from reading other sites' data,
but it also prevents legitimate uses.

Modern web apps often want to get resources from a different origin, for
example, retrieving JSON data from a different domain or load images from
another site into a `<canvas>` element. These can be public resources that
should be available for anyone to read, but the same-origin policy blocks their
use. Developers have historically used workarounds such as
[JSONP](https://stackoverflow.com/questions/2067472/what-is-jsonp-all-about).

*Cross-Origin Resource Sharing (CORS)* fixes this issue in a standardized way.
Enabling CORS lets the server tell the browser it can use an additional origin.

## How does a resource request work on the web?

![](https://web.dev/static/articles/cross-origin-resource-sharing/image/request-response.png) Illustrated client request and server response.

A browser and a server can exchange data over the network using the
*Hypertext Transfer Protocol* (HTTP). HTTP defines the communication rules
between the requester and the responder, including what information is needed to
get a resource.

The HTTP header negotiates the message exchange between the client and the
server, and is used to determine access. Both the browser's request and the
server's response message are divided into a *header* and a *body*.

### Header

Information about the message such as the type of message or the encoding of the
message. A header can include a
[variety of information](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields)
expressed as key-value pairs. The request header and response header contain
different information.

#### Sample request header

```text
Accept: text/html
Cookie: Version=1
```

This header is equivalent to saying "I want to receive HTML in response. Here is
a cookie I have."

#### Sample response header

```text
Content-Encoding: gzip
Cache-Control: no-store
```

This header is equivalent to saying "The data in this response is encoded with
gzip. Don't cache this."

> [!NOTE]
> **Note:** Headers can't contain comments.

### Body

The message itself. This can be plain text, an image binary, JSON, HTML, or many
other formats.

## How does CORS work?

The same-origin policy tells the browser to block cross-origin requests. When
you need a public resource from a different origin, the resource-providing
server tells the browser that the origin sending the request can access its
resource. The browser remembers that and allows cross-origin resource sharing
for that resource.

### Step 1: Client (browser) request

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

### Step 2: Server response

When a server sees this header, and wants to allow access, it adds 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, it shares the response data with the
client site.

## Share credentials with CORS

For privacy reasons, CORS is normally used for anonymous requests, in which the
requester isn't identified. If you want to send cookies when using CORS, which
can identify the sender, you need to add additional headers to the request and
response.

### Request

Add `credentials: 'include'` to the fetch options as in the following example.
This includes the cookie with the request as follows:

```javascript
fetch('https://example.com', {
  mode: 'cors',
  credentials: 'include'
})
```

### Response

`Access-Control-Allow-Origin` must be set to a specific origin (no wildcard
using `*`) and `Access-Control-Allow-Credentials` must be set to `true`.

```text
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true
```

## Preflight requests for complex HTTP calls

When a web app makes a complex HTTP request, the browser adds a
*[preflight request](https://developer.mozilla.org/docs/Web/HTTP/CORS#preflighted_requests)*
to the beginning of the request chain.

The CORS specification defines a *complex request* as follows:

- 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 automatically create any necessary preflight requests and send them
before the actual request message. The preflight request is an `OPTIONS` request
like the following example:

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

On the server side, the app receiving the request responds to the preflight
request with information about the methods the application accepts from this
origin:

```text
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. This allows the
client to send multiple complex requests without needing to repeat the preflight
request.