CORS: what is it for and how does it work?

“Access to fetch https://some-url-here from https://some-other-url-here as being blocked by CORS policy.” Who has never seen this red error inside the Javascript console of your favourite browser?

This article helps you to understand the use of CORS, Cross-Origin Resource Sharing and the way to configure it. Practical examples are provided for Symfony and Django applications at the end of the article.

Cookies and Same-Origin Policy concept

When an HTTP request is made to the backend application, a part of the answer can be stored in a cookie. This piece of information can be a unique session identifier or a token, identifying the user. This token is sent along with every request and the backend server remembers the user is logged. Therefore private data like account details if the app is a bank app can be sent to the frontend.

CORS-authentication

CORS-request-data

If the Same-Origin Policy does not exist, then another website could use the token to call the backend server and get private data:

CORS-anotherapp

This could definitely end badly as the other app does not necessarily have good intentions, as the call from the other app can be made without any user action or consent.

The Same-Origin Policy is enforced by modern browsers to make sure that web application can only make HTTP calls to API with the same origin:

  • If I’m webapp.com I can call webapp.com/api as the origins are the same, webapp.com
  • If I’m anotherapp.com I cannot call webapp.com/api as the origins are not the same

The CORS, the practical way to ensure SOP in a microservices world

When you’ve got a monolithic app, like a Symfony app with Twig to render the views, you’re likely to have one domain for the frontend and the backend of the application.

Nevertheless, with modern frontend technologies as React or VueJS, we tend to decouple the frontend and the backend of the app, and therefore to have two domains. For instance:

  • app.myservice.com for the frontend
  • api.myservice.com for the backend

Thus when you want to make a legitimate request to api.myservice.com will being app.myservice, you encounter this kind of error:

Access to fetch https://some-url-here from https://some-other-url-here as being blocked by CORS policy.

Indeed, the origins are not matching. That’s the point where the CORS enter the game!

The CORS, Cross-Origin Resource Sharing, is a norm to actually by-pass the Same Origin Policy without decreasing the security.

If you want to make the previous request works, the HTTP response should contain a header which is :

Access-Control-Allow-Origin: app.myservice.com

With this header, you make the browser understand that the backend server knows the frontend origin, and it’s not likely a malicious call. 

If you put “*” instead of the domain, you’re removing all security enforced by the Same-Origin Policy thus, it is not a good idea.

You also could have to add a header about the allowed methods:

Access-Control-Allow-Methods: GET, HEAD, OPTIONS, POST

Practical examples


Configure CORS for a Symfony application

If you’re configuring a Symfony application, use the Nelmio Bundle. Register the bundles in the Kernel and then create a nelmio_cors.yaml file in the config folder and add the following CORS configuration:

 

Configure CORS for a Django application

If you’re configuring a Django application, use the Django Cors headers package. Add the Corsheaders to the INSTALLED_APPS array and corsheaders.middleware.CorsMiddleware to the MIDDLEWARE array in your base.py file.

Then add the array CORS_ORIGIN_WHITELIST as an env variable, for instance:

CORS_ORIGIN_WHITELIST = [‘http://app.myservice.com’]

Aurore Malherbes

Aurore Malherbes

Aurore is the CTO of Padok. Previously architect developer, she decided to become Ops to put developers in the best conditions (fast & reliable environments).

What do you think? Leave your comments here !