CORS facilitates the sharing of resources between different origins. Many of us have encountered CORS errors on the client side and may have successfully resolved them. However, let's deep dive into what transpired behind the scenes.
Our browsers enforce the same-origin policy as a part of security measure.
When a request is sent to the server, the request header includes the origin parameter.
If the origin matches, the browser allows the request without further inquiry.
However, if the origin differs, it's considered a cross-origin request. In such cases, the server adds the
Access-Control-Allow-Origin
header to the response, and its value must match the origin specified in the request header.This value can be a specific origin or an asterisk (*) indicating that all origins are permitted.
To resolve CORS errors, server-side control is necessary. For instance, in Node.js (using Express), the cors package can be imported, and the origin can be set to a specific value or an asterisk:
const cors = require('cors');
app.use(cors({origin: 'http://foo.com'}));
Preflighted requests
Unlike simple requests, for preflighted requests the browser first sends an HTTP request using the OPTIONS
method to the resource on the other origin, in order to determine if the actual request is safe to send. Such cross-origin requests are preflight since they may have implications for user data.
Certain methods such as PUT, PATCH, and DELETE require preflight checks. We can set the method in headers like below snippet
app.use({
setHeaders: (res) => {
res.setHeader('method', 'PUT');
})
});
Preflighed request header will look like this:
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
In response server will send an header which look like below.
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: POST, GET,
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Access-Control-Allow-Origin: contains a origin
Access-Control-Allow-Methods: contains all allowed method POST, GET
Access-Control-Allow-Headers: Header adds the specified headers to the allowlist (such as
Response.headers
) in browsers is allowed to access.Access-Control-Max-Age: This indicates how long the results of a preflight request can be cached. For an example of a preflight request
Access-Control-Allow-Credentials
The Access-Control-Allow-Credentials response header informs browsers whether the server permits cross-origin HTTP requests to carry credentials.
Credentials encompass cookies, TLS client certificates, or authentication headers containing user credentials such as a username and password. By default, these credentials are not transmitted in cross-origin requests, as doing so could expose a site to CSRF (Cross-Site Request Forgery) attacks.
A client can request that credentials be included in cross-site requests through one of two methods:
Using fetch(): This involves setting the credentials option in the Request() constructor to "include".
Using XMLHttpRequest: This requires setting the XMLHttpRequest.withCredentials property to true.
If the client has requested the inclusion of credentials:
For preflighted requests, credentials are not included in the preflight request. If the server's response to the preflight request includes the Access-Control-Allow-Credentials header set to true, then the actual request will carry credentials. Otherwise, the browser reports a network error.
For non-preflighted requests, the request includes credentials, and if the server's response does not specify the Access-Control-Allow-Credentials header as true, the browser reports a network error.
Access-Control-Allow-Credentials: true
The Above information draws upon various sources, including the Mozilla Developer Network (MDN) documentation and the the below YouTube video