Golang CORS Guide:
What It Is and
How to Enable It

stackhawk

StackHawk|August 8, 2021

Golang CORS handling is crucial for Go devs. Learn what CORS is, why it matters and how to enable it in Go with this guide.

Security is probably the primary concern of every web app creator. This is true for any language, and Go — often called Golang to make it more searchable — is no exception. Today we're offering you our guide to Golang CORS handling.

So, what's this all about? Well, in a nutshell, CORS is the proper, safe way to get around the restrictions imposed by a security measure. If you have legitimate uses for doing that, CORS is the mechanism that will let you avoid the restrictions without exposing yourself to unnecessary risk.

We'll open with the fundamentals by explaining what CORS is and why it's important. Then, we'll show you how you can enable CORS in your Golang application. For that, we'll provide two applications:

  • a sample Go application that simulates a RESTful API, returning JSON for a single endpoint

  • a React application that consumes the Golang

For the tutorial, we'll assume you have both Node.js/npm and Go properly installed and are familiar with the command line. We'll also ask you to clone two repositories on GitHub, but if there's any problem with that, you can always download the projects as .zip files.

With that out of the way, let's get started.

Golang CORS Handling: The Fundamentals

Before covering Golang CORS in practice, let's understand what CORS is about in the first place.

What Is CORS?

CORS stands for Cross-Origin Resource Sharing. It's a standard web mechanism, based on HTTP headers, that enables a given web server to indicate other origins that are allowed to load resources from it.

In case that sounds a little fuzzy, don't worry. We'll explain in more detail why you need CORS — and also the meaning of origins — in the next section.

What Is the Point of CORS?

To understand the need for CORS, you must take a step back and understand the problem it solves.

Browsers have a crucial security mechanism called the same-origin policy. Due to this policy, browsers prevent websites from loading resources from different origins. Thanks to the same-origin policy, malicious websites can't steal data from legitimate sites.

What is an origin in this context? Browsers will define an origin based on the following pieces of data:

  • The protocol (e.g., HTTP or HTTPS)

  • The port, if available

  • The host

For instance, https://www.stackhawk.com:443 and https://www.stackhawk.com are considered the same origins because protocol, host, and port are the same (port 443 is the default for HTTPS). On the other hand, https://stackhawk.com and http://stackhawk.com are different origins because the protocols are different.

In practice, when is the right time to enable CORS?

The answer is when there are legitimate reasons to create an allow-list of origins that are allowed to load resources from your server. A classical example would be an application composed of a back-end — e.g. a RESTful API written in Java — and a front-end — for instance, an Angular app — when the two are served from different domains.

How Do I Enable CORS in Golang?

Now let's see how you go about enabling CORS in Go. But first, it's important you see the problem happening in the first place.

Let's See the Problem in Action

For this tutorial, we'll assume you have Go properly installed on your system and are familiar with the command line. You'll start by cloning a repo on GitHub:

git clone https://github.com/carlosschults/sample-go-app

Then, access the cloned folder and build the main.go file:

cd sample-go-app
build main.go

Finally, run the built application by executing:

./main

Now you're able to see the application running. Open your browser at http://localhost:8002/articles and you'll get the following result:

[
{
"Id": "1",
"Title": "First article",
"Desc": "Title of this fine article",
"Content": "Content for this fine article"
},
{
"Id": "2",
"Title": "Second article",
"Desc": "Title of this majestic article",
"Content": "Content for this majestic article"
}
]

This is our server written in Go. We now need a client. For this part of the tutorial, you'll need Node/npm installed. Go get them if you don't have them. When you're ready, clone yet another repository:

git clone https://github.com/carlosschults/cors-sample

Then, access the folder and start the project using npm:

cd cors-sample
npm start

Point your browser at http://localhost:3000 and make sure to activate the developer tools in your browser.

You'll see the following error:

Golang CORS Guide: What It Is and How to Enable It image

Understanding the Problem

If you open the contents of the folder you've just cloned using your favorite text editor, you'll see something like this:

Golang CORS Guide: What It Is and How to Enable It  image

This app is a React application that consumes—or at least tries—the JSON returned by the Golang app, converts it to an array of objects, and renders them on the screen.

But, as you could see, that's not working. Why?

The answer is, as you probably suspect, the same-origin policy. The Golang app runs on port 8002. However, the client React app runs on port 3000. As you've seen, simply having different port numbers is already enough for two URLs to be considered different origins. How can we fix that?

In the next section, you'll finally see how to enable CORS in Go and fix the issue.

Fixing the Problem

Let's edit the Go application to allow CORS. Open the main.go file and paste the following function on it:

func enableCors(w *http.ResponseWriter) {
(*w).Header().Set("Access-Control-Allow-Origin", "*")
}

Then, at the start of the handleArticles function, add the following line of code:

enableCors(&w)

The complete handleArticles function should now look like this:

func handleArticles(w http.ResponseWriter, r *http.Request) {
enableCors(&w)
js, err := json.Marshal(Articles)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(js)
}

The next step is to rebuild the Go application and run it again:

go build main.go
./main

Now, if you go to the browser tab in which the React app is running, you should see a result like the following:

Golang CORS Guide: What It Is and How to Enable It image

It works! As you can see, now the React app is able to successfully retrieve the articles from the Golang app.

There's still one final change we can make to the Go application. Take another look at the main.go file, specifically at the enableCors function, and you'll notice this:

(*w).Header().Set("Access-Control-Allow-Origin", "*")

As you can see, we use an asterisk when setting the Access-Control-Allow-Origin header. What that means is that we're opening up our application to all possible origins. This is practical when testing, but it's obviously not secure. Let's change that line to this:

(*w).Header().Set("Access-Control-Allow-Origin", "http://localhost:3000")

Now we're explicitly setting the address http://localhost:3000 as the allowed origin.

Go Make Your Apps More Secure!

As you've seen in this post, the same-origin policy is a crucial security mechanism for the web. Without it, it would be possible for scripts from one origin to load data from other websites, making attacks and data theft easier.

However, sometimes you'll have legitimate reasons for accessing secure data, and that's where CORS comes in handy. CORS is a mechanism you can use on your web app to indicate other origins that are allowed to load from its resources. In this post, we've covered some fundamentals about CORS and how to enable it in a Go app.

Bear in mind that what we've covered here today is just the tip of the iceberg when it comes to CORS. For instance, something we haven't discussed here is pre-flight requests, which are needed when performing requests with verbs others than GET. Also, for real world scenarios, consider adopting a dedicated package for handling CORS in Golang, such as this one.

Thanks for reading, and until the next time.

This post was written by Carlos Schults. Carlos is a consultant and software engineer with experience in desktop, web, and mobile development. Though his primary language is C#, he has experience with a number of languages and platforms. His main interests include automated testing, version control, and code quality.


StackHawk  |  August 8, 2021