CORS : Simple vs Preflight request
Narrative
CORS, preflight requests in a nutshell, There are active topics in stack overflow about CORS and the preflight request and the reasons why it is needed. I am collating the key aspects of the same concept’s implications and repercussions drawn out of this scenario.
What is CORS?
In order to relax the same origin policy CORS helps modern browsers to achieve cross domain resource access. CORS (Cross Origin Resource Sharing) is a simple mechanism to let a web app running at one origin to access resources securely at another origin with permissions(via headers if applicable). This permission is more of a mechanism with headers for security reasons standard, as browsers restrict cross-origin HTTP requests initiated from within scripts to help mitigate the risk. I am not going to dwell around CORS as there are enough articles to refer to, lets evaluate actual reason for preflight request.
Why Preflight request?
As per the W3C specification(For HTTP request methods in particular, other than GET or POST with certain content types), browsers first makes the preflight (OPTIONS request ) in order to validate whether the supported methods are valid from the server. When the browser get a valid response from the server, then it makes the request with the actual HTTP request method. Servers can also notify clients that cookies and HTTP Authentication is mandatory & should be sent with requests as it depends on the end point configuration. Also the server should validate the Origin header to ensure that it is allowed to make the cross origin request.
We cannot force browsers avoid the options request in case of non simple requests type.
How can we avoid Preflight request?
Simple request
This is clear from CORS specification that preflight request is not mandatory in case of Simple requests ( if all of the following conditions are met )
If the method is
GET/HEAD/POST
If we manually set headers like
Accept, Accept Language, Content-Language, Content-Type(refer below for more conditions )
If we set only the following Content Type
application/x-www-form-urlencoded or multipart/form-data or text/plain
The above specifies the major conditions for a simple request, For more details please refer to the CORS articles or w3c CORS specification.
Final Inference
- If we are not doing the simple request, then its obvious to enable OPTIONS http request on the server side to enable a successful preflight request by any browser.
- If you already have a simple HTTP request like GET or POST but you intend to specify the content types other than above then please enable the CORS with OPTIONS preflight request else the API request fails.
- If any of the API needs token for authorization, then it is advisable to set it in Authorization header for sending Bearer or Basic access token, in such a scenario for preflight request we could do one of the following
if POST, we can enable OPTIONS for preflight as the client needs to send the Authorization Header in the request
if GET, we can set CORS to allow additional header (Authorization) and can avoid OPTIONS preflight. ( could be applicable for POST )
P.S.
1. the above settings could be set at API Gateway level (recommended) or at the direct service/server level.
2. In API gateway, Value for the
Access-Control-Allow-Headers
header, expects a comma delimited string (e.g.Origin, Authorization
) instead of * which could be vulnerable for CSRF
Caching Preflight
In addition to above settings, we can even cache preflight request so that until the cache expires preflight request could be avoided.
- API gateway (Most of the plugins/policies )
max_age
Indicating how long the results of the preflight request can be cached, inseconds
.
2. Header config on server side
The
Access-Control-Max-Age
response header could be set to a value in seconds which specifies the caching time for preflight request (that is the information contained in theAccess-Control-Allow-Methods
andAccess-Control-Allow-Headers
headers) can be cached.
Please refer to the articles below for more details & Follow on LinkedIn
Image Reference
image source : Mozilla
Other References
<style>
.libutton {
display: flex;
flex-direction: column;
justify-content: center;
padding: 7px;
text-align: center;
outline: none;
text-decoration: none !important;
color: #ffffff !important;
width: 200px;
height: 32px;
border-radius: 16px;
background-color: #0A66C2;
font-family: “SF Pro Text”, Helvetica, sans-serif;
}
</style>
<a class=”libutton” href=”https://www.linkedin.com/comm/mynetwork/discovery-see-all?usecase=PEOPLE_FOLLOWS&followMember=rpradeepkumar” target=”_blank”>Follow on LinkedIn</a>