Before defining CORS, some fundamental concepts to understand CORS will be defined.
Given a URL, the origin is the first part that is made up of the scheme: the host and the port (if present).
source = scheme + host + port
For example, in
https://localhost:8080/surveys the source is
/survey is the path
It refers to the case where the client makes a request to a server and the server has the same origin as the client.
https://aurora.net/home -> https://aurora.net/api/pos?id=290
The client makes a request to a server whose origin is different from that of the client.
https://localhost:8080/home -> https://aurora.net/api/pos?id=290 https://localhost:8080/home -> https://127.0.0.1:8080/api/pos?id=290 https://localhost:8080/home -> https://127.0.0.1:3000/api/pos?id=290
By default and by security policy, browsers only allow HTTP requests to the same origin, that is, to the same domain as the page that makes the request.
CORS (Cross-Origin Resource Sharing) is the mechanism by which browsers allow a request to be made from one origin to a different one, cross-origin.
In order to make a CORS request, the client does not have to do anything, it simply launches the request. The browser makes the request and it is the server that must respond if it accepts requests from that origin. It does this by sending the
Access-Control-Allow-Origin header response. This header can have an asterisk (
*) or a specific origin. The
* means that the server accepts requests from any origin.
The browser reviews the browser's response. If you have the
Access-Control-Allow-Origin header and it has the value
* or the origin matches the client origin, then the browser accepts the response. Otherwise, it discards it and generally displays a CORS-descriptive error on the console.
1. browser with origin X makes a request to origin Y 2. server responds 3. If the response from the server includes the header `Access-Control-Allow-Origin` Then 4. If (Access-Control-Allow-Origin == '*') or (Access-Control-Allow-Origin == X) Then 5. browser accepts the response 6. If not 7. discard response and show error 8. End Yes 9. If not 10. discard response and show error 11. End Yes
Access-Control-Allow-Origincan also be set to
nullfor unknown origins (such as accessing from a file instead of a website). This is useful while you are in a development or testing phase, this way you don't need to put '*' which is less restrictive.
Above we have seen in a generic way how a cross-origin request should be treated using CORS. Actually, before making a cross-origin request, browsers that implement CORS will "meta" the actual request.
A preflight is a request that the browser makes before making a CORS request if the request meets one of these criteria:
- Use an HTTP method other than
- Set the
Content-Typeheader to a value other than: -application/x-www-form-urlencoded
- multipart/form-data -text/plain
- Set additional headers other than:
- The XMLHttpRequest object contains upload events
The HTTP methods
HEADare called simple methods. Simple methods do not need to be listed in the
The preflight is a request with the
OPTIONS HTTP method. This "meta" request that the browser makes is for the server to decide how to respond to CORS. In the preflight the browser sends the headers:
Access-Control-Request-Method(supports only one method)
Access-Control-Request-Headers(only if the headers are not simple. You can have a comma-separated list of headers)
The server checks if the HTTP origin and method are in its list of allowed origins and methods (it will also check the headers indicated in
Access-Control-Request-Headers, if any). If this check is favorable, it responds with a status code in the range
200. The answer should not wear a bodysuit. The headers sent by the server are:
Access-Control-Allow-Methods(in this case it can be a comma separated list of commands)
Example of preflight request:
OPTIONS /api/posts HTTP/1.1 User-Agent: Chrome Host: 127.0.0.1:8080 Accept: */* Origin: http://localhost:3000 Access-Control-Request-Method: GET Access-Control-Request-Headers: Security-Level, App-Name
Example preflight response:
HTTP/1.1 204 No Content Access-Control-Allow-Origin: http//localhost:3000 Access-Control-Allow-Methods: GET, DELETE Access-Control-Allow-Headers: Security-Level, App-Name
GET /api/posts HTTP/1.1 User-Agent: Chrome Host: 127.0.0.1:8080 Accept: */* Origin: http://localhost:3000 Security-Level: High App-Name: Survey
The previous algorithm, now modified with the preflights, would look like this:
Cache. The browser can cache the preflights and thus avoid making an extra request for each client request that would require a preflight. The cache saves on its origin + path entries.
For images whose
src attribute is a different origin than the client, the browser loads the resource and displays it but does not allow manipulations with it such as
To enable CORS in the case of images, there is the
crossOrigin attribute that can take the values
user-credentials is like
withCredentials in XMLHttpRequest, ie user credentials (eg cookies) are sent with the request. If it is not necessary to send the credentials, it is preferable to send
By default the browser does not send user credentials as cookies in cross-origin requests. The browser also does not expose all the response headers that the server sends.
That's why CORS has mechanisms to remedy those restrictions: the
Access-Control-Expose-Headers response headers.
xhr.withCredentials = true; document.cookie = someUniqueId;
The server must respond to the preflight and the request with the headers
When the server sends the
Access-Control-Allow-Credentials header with the value
true, it must send the
Access-Control-Allow-Origin header with a specific origin;
Access-Control-Allow-Origin: * is invalid because accepting cookies from any origin can cause security problems.
Access-Control-Allow-Origin: http://localhost:1111 Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: \* Access-Control-Allow-Credentials: true
In the case where the client has
xhr.withCredentials = true and the server responds with
The XMLHttpRequest object exposes two methods for reading response headers:
getAllResponseHeaders. In a same-origin request these methods return all the headers sent by the server. When dealing with a cross-origin request, only the plain headers can be read.
Access-Control-Expose-Headers header the server can specify which headers the client can read.
Origin: Header added by the browser. Contains the origin of the client in the request. Counterpart:
Access-Control-Request-Method: Header added by the browser in the preflight. Contains the HTTP method that the client will do on the actual request. Counterpart:
Access-Control-Request-Headers: Header added by the browser in the preflight. Contains the HTTP headers that the client will send in the actual request. Counterpart:
Access-Control-Allow-Origin: The value
*indicates that all origins are allowed
A specific value indicates that the server only accepts requests from that source
nullindicates that it only accepts requests from sources that are not a web site, for example a file (only recommended for development and testing). Counterpart:
Access-Control-Allow-Credentials: The value
trueindicates that the server supports the use of user credentials such as cookies.
Access-Control-Allow-Methods: Has a list of HTTP methods accepted by the server.
It is not necessary to include the simple methods, although it is good practice to do so.
This header should only be sent in response to preflight requests. Counterpart:
Access-Control-Allow-Headers: Has a list of HTTP headers accepted by the server.
This header should only be sent in response to preflight requests. Counterpart:
Access-Control-Max-Age: Its value specifies the maximum time in seconds that it is recommended to keep a preflight cache, although the browser can have its own maximum value.
This header should only be sent in response to preflight requests.
Access-Control-Expose-Headers: Contains the headers that can be read by the browser. You can have a comma separated list of headers.
It is optional and is not required for the CORS request to be successful.