The minimum every developer must know about CORS
What is CORS?
- CORS stands for Cross-Origin Resource Sharing.
- CORS is HTTP-header based mechanism set by server to inform client side about allowed origins (
<scheme>://<hostname>:<port>
) other than its own. It also indicates method and headers which the server is willing to support (example included below). - Most of client browsers enforce CORS whenever a cross-origin request is made. A request is cross-origin if it calls to outside origins, which are different from the one served the first resource.
CORS behaviour will be different between simple & “pre-flighted” requests. Let’s see the detail below.
Simple requests
- Refer here for full definition of simple request. For example, a GET request with no header is a simple request.
A simple request is sent directly to server.
Source: MDN web docs
- Request 1: Client browser first load a web document from
domain-a.com
. The main request defines itsorigin
asdomain-a.com
. This origin is then specified in the request header of subsequent requests.Origin: <origin>
- Request 2: Client browser then send request to GET resource from
domain-a.com
. As comming from the same origin, the requested resource is fetched & rendered by browser. - Request 3: similar to request 2, but the request now is sent to
domain-b.com
, which is a different origin.- The resource will be successfully fetched, but ...
- It might be rendered by the browser only if in the response header, the allowed origin ==
domain-a.com
(the request origin) or when it is a wildcard (*) meaning permit all origin.Access-Control-Allow-Origin: <origin> | *
- Request 1: Client browser first load a web document from
“Pre-flighted” requests
- Any requests that are not simple is “pre-flighted” one.
Unlike simple request, the browser will send a “preflight” request (OPTION method) to see if the actual one (”pre-flighted” one) is allowed by the server.
Source: MDN web docs
A preflight request will include the following headers:
Origin: <origin> Access-Control-Request-Method: <method> Access-Control-Request-Headers: <field-name>[, <field-name>]*
- To inform server about method and headers used in the actual request.
- To ask if the server allow client origin with given headers & method.
- Server responses with the following headers if it supports:
Indicating origin, method & headers the server supportsAccess-Control-Allow-Origin: <origin> | * Access-Control-Allow-Methods: <method>[, <method>]* Access-Control-Allow-Headers: <header-name>[, <header-name>]*
- Then, the browser will compare value in the response header against corresponding info of the actual request. If all is allowed, the actual request is sent; otherwise, not.
- The preflight request can also be cached in client side with the time-to-live indicated in
Access-Control-Max-Age
response header
Final note
CORS is server-side security configurations that clients may enforce it.
- Most browsers do (to avoid attack like CSRF).
- Some dev tools do not (like Postman).
Further reading & references:
This article just covers surface of CORS. Further reading is highly recommended!
- Detailed visualization example: https://www.youtube.com/watch?v=Ka8vG5miErk&t=621s
- Further analysis: https://www.stackhawk.com/blog/what-is-cors/
- Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
Follow me (@vietmle_) on Twitter to get update whenever my new article is out!