CORS stands for Cross-Origin Resource Sharing and represents a method of accessing/sharing resources across domains. These resources can be anything from web fonts to APIs. The CORS standard is only implemented in browsers, since this is the only place where it makes sense. While this is the preferred method of sharing resources, it has a few rough edges.

The Basics

In the following we’ll refer to the response headers, since the request headers are automatically set by the browser.
A special header defined in the CORS specification must be sent by the server in each response to allow access to a resource:

Access-Control-Allow-Origin: allowed-domain.com

To allow any domain to access resources the header can be set to a wildcard:

Access-Control-Allow-Origin: *

This is the bare minimum and it will suffice for sharing static resources such as web fonts. But once we throw in authentication, which is needed by most APIs, things get messy.

Authentication

Authentication, with either cookies or HTTP auth, requires an additional response header:

Access-Control-Allow-Credentials: true

Also the browser needs to send cookies/credentials in the request, so for example in JavaScript we need to pass an additional parameter to XHR object:

var req = new XMLHttpRequest();

req.open('GET', url);
req.withCredentials = true;
req.onreadystatechange = handler;
req.send();

A few notes on authentication:

  • We cannot use domain wildcards for the Access-Control-Allow-Origin header when allowing credentials. The domain must be explicitly stated. This is a feature to prevent CSRF.
  • Credentials are not allowed with synchronous requests in some browsers, since these requests cannot be pre-flighted.
  • IE and Opera were slow to adopt CORS; only IE 10 and Opera 12 support it properly.

Pre-flighted requests

Some cross-origin requests are pre-flighted, meaning that an OPTIONS request is automatically sent by the browser before each request, to query the server for allowed HTTP methods, allowed headers or to check whether credentials are allowed.

OPTIONS requests are only sent if any of the following conditions are met:

  • The request method is other than GET or POST.
  • The request Content-Type is other than application/x-www-form-urlencoded, multipart/form-data or text/plain.
  • Custom headers are set.

Obviously, sending OPTIONS before each real request has a bit of overhead. Fortunately, there is a header that tells the browser to cache these requests:

Access-Control-Max-Age: 86400

Allowing methods and headers

In order to create RESTful APIs we need to use more than the GET and POST verbs.
Servers can inform the clients of the allowed HTTP methods by using another type of CORS header:

Access-Control-Allow-Methods: GET, POST, PUT, DELETE

Any number of HTTP verbs can be listed here.
Allowed headers can be set with:

Access-Control-Allow-Headers: Origin, X-Reqested-With, Accept

X-Reqested-With is needed for asynchronous requests.

All these headers except Access-Control-Allow-Origin are commonly included only in the pre-flight response.

IE support

As always, IE chooses to hit developers with a crowbar.
Instead of extending XMLHttpRequest, IE 8 introduces another interface named XDomainRequest, with a similar interface, which supports CORS, but not its full set of features.
Luckily IE 10 fixes this and adds support for CORS within the standard XMLHttpRequest.

Further reading