CORS and Same-Origin Policy Basics
Have you ever tried to fetch data from an API, or load an external resource in your application and seen a red error message on the console along the lines of
No 'Access-Control-Allow-Origin' header is present on the request resource. Origin XYZ is therefore not allowed access...?
When I first started out writing web apps, I had a somewhat surface-level understanding of what that error meant - Turns out it’s one of the most important rules that govern the web. In this post, we’ll take a brief look at important basics all front-end engineers should know about Same-Origin Policy, CORS and JSONP.
One of the oldest rules in the web is the same-origin-policy. What exactly does this mean? An origin on the web is made up of three parts : Data Scheme, Hostname, and Port :
https:// google.com /433 <Data Scheme> <Hostname> <Port>
On the web, we’re only allowed to request resources if it’s from the same origin. Meaning, from
https://www.domain-A.com, I can’t make a request to
The same goes for images as well. You can’t interact with an image from another origin the same way you would with an image from your own origin - You won’t be able to inspect the pixels from inside the canvas element, for example. The same-origin policy is critical because it will prevent me, for example, from making a request to my friend’s facebook to fetch all his messages. Another important thing to point out is that it’s the client-side, the user’s browser that enforces same-origin policy, NOT the server.
JSONP and CORS to the rescue
Before CORS was adopted most browsers, JSONP was the method of choice for getting around the same-origin policy. JSONP, or JSON with Padding, is a clever and simple way of getting data from a foreign resource. It exploits the fact that while you aren’t allowed to make an ajax request to a foreign origin, you ARE allowed to include a
<script> tag from a different origin. How you implement JSONP is very straightforward :
- Create a new script tag, and set the src attribute to the endpoint you want to request data from
- Inside the src attribute, include a callback function that will be executed
- Once the script loads and executes, the script will invoke the callback function with the data from the origin
JSONP is simple but obviously very limited. Since it’s read-only, it’s limited to GET requests and is best served for simple services like News APIs and the weather.
CORS, or Cross-Origin Resource Sharing on the other hand, is the de facto solution for making cross-origin requests. CORS enables servers to specify a set of origins(Like a whitelist) that are allowed to access its resources. For example, in one of my past projects, Leaflet, I made calls to my Book Review site using the WordPress API and had to enable CORS on the server in order to allow for the Leaflet app to make fetch requests.
An important thing to point out is that it’s the response that’s blocked. Meaning, when a browser makes a request to another origin, the request itself will go through, but if CORS isn’t enabled the response will come be blocked.
This is critical in the case of PUT requests - If we made a PUT request to another resource, since the request itself goes through, the POST request can potentially have a destructive effect on the foreign origin on the server. It wouldn’t matter if the response is blocked, the damage would have been done anyway.
That’s why for POST requests, CORS actually does something called pre-flight checks. Before sending out POST requests, CORS will first send an OPTIONS request to do a pre-flight check, and only if it gets back a header from the server saying, ‘You’re good to go, I recognize you as someone I’ve allowed to make requests to me’, it will then make a PUT request.
For more information on CORS, check out the MDN Docs, as well as a fantastic tutorial by HTML5Rocks. Now that you’re armed with an understanding of the same-origin policy, hopefully you can comfortably handle
Mixed-Content errors and
No Access-Control-Allow-Origin errors.