Implementing CORS with Gorilla

Introduction

During the last week of my pairing tour, I had the opportunity to pair with James C and his client for two days. We set up CORS functionality on the client’s app and attended a few meetings. Although I did not get a chance to do much coding during the two days (we were mostly sifting through documentation), I did contend with a metaphorical firehose of new information. I want to use this blog post to organize what I learned about CORS and provide a small demonstration of the concepts.

We mostly referenced the ASP .NET configuration page during our work. Afterwards, I supplemented the information from that document with the MDN CORS article and the Gorilla Web Toolkit website. Additionally, You Don’t Need JQuery provided some excellent examples of AJAX and CORS using the XMLHttpRequest object. Although I am only going to demonstrate a simple CORS example with a GET request, these are great sources if you want to dive further into the standard.

Background

Websites in your browser conform to the same origin policy. The origin of a resource (e.g. HTML, images, Javascript, etc.) is defined by the domain name and port from whence it came. The same origin policy mandates that resources of one origin can only interact with resources of the same origin. This means that two different websites in two different tabs of your browser cannot interact with each other (specifically, the Javascript that is run in one browser tab cannot access any of the resources of the other tab). This is a very good thing because it prevents malicious websites from accessing private content by manipulating the tabs of a browser.

However, this setup is not always ideal. Sometimes developers want to access resources from other websites in order to prevent excessive duplication of content. Other times, developers might use a different domain to host asset data in order to optimize performance. Mozilla Developer Network lists a number of other reasons why a developer might want to access content from a different origin:

  • Invocations of XMLHttpRequest
  • Fetch APIs
  • Web Fonts
  • WebGL Textures
  • Images or Video via “`drawImage“`
  • Stylesheets for CSSOM access

Thus, the single origin policy can be stifling to developers. Cross-origin resource sharing (CORS) is one method that can be used to safely share resources between two origins.

In the CORS standard, one uses HTTP headers to describe the origins that are permitted to access resources via a web browser. Requests that do not change state (such as GET) can directly ping the server for content while requests that alter the state of the server (such as PUT) need to exchange appropriate credentials with the server beforehand – a process called the “preflight”. Due to the exchange of information between clients and servers, CORS requests can gracefully handle cookies and HTTP authentication data.

In the series of examples below, I am going to demonstrate how to set up a server with CORS credentials using Go and Gorilla. Then, I am going to send a CORS request to the server via XMLHttpRequest from a website using the console in Chrome’s Inspector tool.

Failing CORS Requests

I have become very fond of Go recently due to the fact that you can create robust APIs in just a few lines of code. Let’s start off with a simple server with one endpoint and no CORS functionality:

https://gist.github.com/cmvandrevala/c3842af274134990e092d1074e080a4a

If I start up the server and then navigate to http://localhost:3000 in my browser, I will see the phrase “This is a cool message!”. Everything seems to be working as we might expect. After reading up on the XMLHttpRequest object, I determined that I could send a request to my server via the following commands:


var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:3000');
xhr.onload = function() { console.log(xhr.responseText); }
xhr.onerror = function() { console.log("There was an error!"); }
xhr.send();

The code above creates a new XMLHttpRequest object and opens a connection to my server. If the response loads without error, then it simply prints the text to the console. If there is an error, we get an error message. I will navigate to google.com, open up the Inspector tool and type the request in at the console.

https_error.png

Uh oh. It looks like my server uses HTTP while Google uses HTTPS. Although I could set my server up to use HTTPS, I will just navigate to a website that uses HTTP (the landing pages of many websites uses HTTP instead of HTTPS). I used StackOverflow. I type the commands in again and get some new output.

no_cors.png

Ok, this makes sense. Right now I do not have CORS set up on my server, so the browser is blocking the request. Let’s set up CORS on my server and see what happens.

Passing CORS Requests

In the code below I import Gorilla handlers to set up CORS on my server. I create a CORS object (“corsObj“`) that will manage the list of allowed origins that can access my endpoint. Right now, I am setting up the handler to accept CORS requests from any origin to any endpoint (even though I only have one endpoint here). Of course, in production, you definitely want to restrict access to only what is necessary. I pass the CORS object into the server when it is started.

https://gist.github.com/cmvandrevala/9201cf9745eb14b6cc8c09e51c00e8fc

If I navigate to localhost:3000, I see the message “This is CORS in action! Woot!”. That works as I expect. Now, when I try to send the CORS request from the StackOverflow landing page, I get a different message.

working_cors.png

Now the request works! That is CORS in action!

Final Thoughts

I only scratched the surface of CORS in the post. There are a multitude of other things to think about including the CORS library that you are using in the server, the format of the returned data, authentication, HTTP vs. HTTPS, and the overall design of your backend. I will certainly be exploring these topics in the weeks to come.

Leave a comment