DEV Community

Rahul
Rahul

Posted on

CORS & Preflight Request!

What is CORS?

CORS - Cross-Origin Resource Sharing
In simple terms, when you want to allow requests from a different domain (read origin) to your server, CORS comes into the picture. CORS is a policy that is enforced by the browser.

But what is Cross-Origin? 🤔

Let's say you're reading this post on Dev.to. Dev.to is the origin here and it's allowed to request for resources (make https calls) that are present in its origin only. If it's making calls to any other origin, even to its sub-domain, the request will be termed cross-origin request.

Show me a use case!

In the world of microservices, even within your architecture, you might have different services talking to multiple servers. CORS is a mechanism to let only the trusted origins make the Cross-Origin HTTP request to your server.

Consider this naive example where there's an application running at rahul.dev.to and there's a functionality to edit my posts. Once the post is edited, I have to update the post across all my blogging sites - dev.to, medium.com, blogger.com

For this hypothetical case to work, I would need to hit this patch API on dev.to.

PATCH https://dev.to/rahul_ramfort/post/20
Request-Headers: User-Agent, api_key

(for brevity, ignoring medium and blogger API calls)

I am trying to post the data from my server (rahul.dev.to) to another server (dev.to) and I might or might not be allowed to actually make this request on dev.to.

This is the problem at hand. Browsers do not know if it's safe to make this request.

Enter Preflight Requests! ✈️

To solve this, Browsers for security reasons, do not directly allow this cross-origin requests to go through. Before firing the actual patch request, it instead fires an OPTIONS request to the cross-origin (dev.to) with all the details of the CORS request.

The details include:

Origin of the requested server - rahul.dev.to
Method rahul.dev.to is trying to hit - PATCH
Headers rahul.dev.to is trying to send - User-Agent, api_key

Dev.to, the cross-origin receives the OPTIONS request and can deny or allow the origin (rahul.dev.to) to make requests.

In this case, dev.to would have configured a list of trusted origins that can make the CORS requests at its application layer.

#sample configuration at the nginx layer (dev.to)
'Access-Control-Allow-Origin' "https://api.dev.to, https://rahul.dev.to"
'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT, PATCH'
'Access-Control-Allow-Headers' 'User-Agent,Content-Type,access-key,api-key'
'Access-Control-Max-Age' 86400

If rahul.dev.to is listed as one of the trusted origins, the browser receives a successful 204. Now the browser understands that it is safe to allow the CORS request and fires the actual PATCH request.

CORS request

If rahul.dev.to is not listed in the allow-origin, the server denies the OPTIONS request.

The browser considering this as a potential threat, will not fire the actual PATCH request throwing an error,

Preflight response is not successful

Understanding the CORS response headers:

These are the headers received for the preflight request.

  • Access-Control-Allow-Origin - specifies the requested origin if it has access.
  • Access-Control-Allow-Methods - specifies which methods are allowed for CORS.
  • Access-Control-Allow-Headers - specifies which headers can be used with the actual CORS request.
  • Access-Control-Max-Age - specifies how much time (in seconds) the response of the preflight request can be cached. The browser will skip further preflight requests and directly hit the actual request during that time period.

Note:

Access-Control-Allow-Origin: '*'

It is pretty common to see people configuring like this as a workaround to allow CORS requests.

What this essentially means is that your server is allowing all the origins to hit CORS requests. No, do not do this. 🙅🏻‍♂️ Allow only trusted origins here and using '*' should totally be avoided.

Further, if you want to reduce the frequency of preflight requests for your trusted origins, you can set the Access-Control-Max-Age header to a higher value.

To read more: 📖

Latest comments (3)

Collapse
 
harshilparmar profile image
Harshil Parmar

Nice brother!!
Can I ask one question?

Access-Control-Allow-Headers - specifies which headers are accepted with the actual CORS request (in this case PATCH)
why are you saying PATCH is a header?? From my knowledge it is method right?

Collapse
 
rahul_ramfort profile image
Rahul

Yes, you're right. Patch is a method.

But what I meant was
"Access-Control-Allow-Headers - specifies which headers will be accepted with the PATCH request that is to follow"

Yes, it's kind of misleading, I'll rephrase this.

Collapse
 
harshilparmar profile image
Harshil Parmar

👍👍