Posted on 15 April 2020, updated on 29 August 2022.
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.
If the Same-Origin Policy does not exist, then another website could use the token to call the backend server and get private data:
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’]