A CORS Is A CORS, Of Course Of Course
Understanding CORS (Cross-Origin Resource Sharing) And Its Role In Browser Security
CORS (Cross-Origin Resource Sharing) was something very briefly mentioned when I was first introduced to creating full stack web apps in phase 3 at Flatiron School. As I tried to get my first ever made-from-scratch app up and running, I got an error that told me that the backend API would not be sending data to the front end. A CORS error.
But what is CORS? In short, it’s a mechanism that allows one website/URL to request data from another website/URL. This is for security: if data from any other origin (malware) is sent back to our browser, it is blocked by CORS. That’s why, if you’ve ever tried to figure out anything from the error message, you’ll notice that the failure messages are intentionally left vague. CORS is trying to protect the security of the requester. If both sides of the server request are from the same origin, CORS is not enacted, and information is able to pass freely. If the two sides of a server request are from two different origins, CORS (cross-origin resource sharing) comes into play to allow the transfer of data.
Before we can get into how CORS lets us share data between two different origins, let’s establish what origin even is.
Three things determine a website’s origin: the protocol, domain, and port. I’ll go over them briefly here, but I highly recommend taking some time to look into these three aspects of website origins in more depth.
There are many different internet protocols, but the two most commonly seen are http:// and https://. HTTP (hypertext transfer protocol) handles request methods and header fields (common internet requests), while HTTPS (hypertext transfer protocol secure) does the same things, but over a secure network to protect information, such as when shopping online or viewing a bank account.
Domain is typically what we think of as the website’s name. The domain for www.google.come is Google, www.espn.com has the domain ESPN, etc. Again, this is a simplification, and I highly encourage taking some time to dive more into this on your own.
The port of a website origin is the communication endpoint for the network carrying across the information. They are always associated with an IP address, and specific numbers correspond to different tasks/services being done. Common ports that web developers will see when working on a project are :3000 and :4000, the two most common local host ports (“http://localhost:3000/”).
So if all three of these aspects of a web origin match the database or web page it is making a request to, CORS is not needed, because we are not sending a cross-origin request. This is called the Same Origin Protocol.
CORS acts kind of like security badges at an office building. If you work for that company, you can just swipe your badge and enter through the front door, and begin accessing information from the company with no issue.
Let’s say you work for a website called www.cuteCatPics.com. If you, as a cuteCatPics.com employee swipe your badge at the door, you’ll be granted access and can start looking through the files of cat pictures inside. You’ll be allowed to take any photo in the building and put it where you deem fit, because the company has the same origin as you, and therefore trusts you. This is essentially what is happening when we make same origin requests to a database.
But what if you want to use a specific font from www.coolFonts.com? If you go over to that office building and try to go inside to grab that snazzy font, your badge won’t work. You’re not a coolFonts.com employee, you have a different origin than that company, so you are denied access.
This is essentially why I received a CORS error when I was building my first full stack web app. The backend API was rendered on http://localhost:4000/, while the front end server was rendered on http://localhost:3000/. Because they were coming from two different ports, the backend denied access to the front end server.
Solving the CORS error
For CORS to be approved, we need to set the origin header (request) to match the Access-Controls-Allow-Origin header (response), or this can be set to the “*” wildcard, which allows any url .
If you’re using Ruby on Rails as a backend framework, the gem Rack CORS (docs linked in helpful resources at the bottom) allows you to set the origin header of your request to the origin you are sending to. This is how I utilized this gem for my phase 3 project. Navigate to:
Set the origins to the specific web origin(s) you want to gain access to. Continuing from my example before, I am requesting access to information at the origin www.coolFonts.com.
An alternative to specifying your intended origin is to simply put “*” (a wildcard) in the origins. While this will allow access to any origin, it is not secure, as any origin (good or bad) can send back information to your server. I encourage avoiding using the wildcard as much as possible.
Specific HTTP Requests Do Not Require CORS
There are a few HTTP requests that do not trigger a CORS response; these are called Simple Requests.
A simple request uses one of the allowed methods for a foreign origin:
This is a major simplification, and simple requests definitely can be determined by other factors. I highly encourage looking into the resources at the bottom of this blog to further understand simple requests.
So what requests do trigger CORS? The HTTP requests PUT, PATCH, and DELETE do, because they have non-standard headers. These can be preflighted. A CORS preflight request checks to make sure that permissions are established for the required HTTP request types. A preflight request is found in the origin, and uses three HTTP request headers: the origin header, the Access-Control-Request-Headers, and the Access-Control-Request-Method.
Similar to the way that passengers can be prepared to go through TSA before boarding a plane, browsers can have their HTTP requests prepared for inspection by servers if the request will trigger a CORS response. Luckily for the web developer, preflight requests are automatically created by the browser, and web developers typically don’t need to include any additional information in the code.
Again, let’s use the example of a coolCatPics.com employee trying to get a font from coolFonts.com. If coolFonts.com knew that you were going to head over to the office and make a request to enter the building, they would send a pre-entry survey. As long as you filled it out and had your paperwork ready at the door, coolFonts.com would have a visitor badge ready for you, and you would be granted access to the fonts inside!
CORS is essentially an attempt by the browser to keep information secure. This is accomplished by expressing specifically what servers or other websites information can be received from. Hopefully this blog helped unravel the reasons CORS errors happen. There are many other aspects of CORS that I didn’t cover here, such request headers, requests with credentials, and use of a proxy. I’ve listed a few helpful references to hopefully help explain things further!
Using the Rack Cors Ruby Gem: https://www.rubydoc.info/gems/rack-cors/0.4.0
Docs for Simple Requests: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests
A Shot of Code’s youtube explanation
Fireship’s 100 second youtube explanation
Karen White’s blog about CORS
Deepak Kumar’s blog on CORS