Github OAuth in Go
By: Dakshraj Sharma
Tags: Dev, Coding, Software Development, Go, Github

Github OAuth with Go

Because do you really need to implement your own authentication service?

You’ve probably come across a number of applications with the “ Login with Github” option, and why not — developers love Github more than Google or Facebook. When developing your own side-projects, you often want to implement some sort of authentication or user-data management. But you really don’t need to implement your own authentication services for every project — OAuth using applications like Github does the job perfectly well.

Why should I use Github OAuth, and not my own, superior, custom authentications service?

Using Github OAuth over your own solution has several advantages:

Github’s authentication and data management approach is probably better than yours (please don’t be offended).

Convenient for users, since they won’t need to manage another password.

Quicker to implement (compared to your own solution). This is a very important, but perhaps neglected point for developer side projects. You don’t want to spend forever on a single project (unless you really know you do).

Simple to understand and implement.

Okay, I might try it. But how does it work?

Let’s try to understand the authentication through the following diagram.

Github OAuth Flow

What’s happening here? Let’s go step by step.

First, the client (frontend) navigates to a route designated for the GitHub login. Say, ‘/login/github’.

When this route is fetched from the server (GET request to the server), the server redirects the user to a special github.com route where he can authorize the application. The route is of the form:

Here, the user will log in to GitHub (if not already logged in), and on the next page, authorize the application to his information.

Once the user accepts, the Github API sends a request to the redirect_uri specified in the earlier request (/login/github/callback in this case). The request gives us a ‘code’ as a query parameter. We extract this code. This will be used later for getting user data.

Next, we send a request to the GET endpoint

https://github.com/login/oauth/authorize

As query params, we send our client id and client secret (which we generate in our Github account) as well as the code we acquired in the last step. Here, at this step, we can be assured that the returned data will be valid as it comes directly from Github.

The above request gets us a response in the following form:

access_token=e72e16c7e42f292c6912e7710c838347ae178b4a&token_type=bearer

The server needs to extract the access_token from this request, and use it for its final request for data.

Now, the server sends a GET request to the endpoint, with the



GET Authorization: token e72e16c7e42f292c6912e7710c838347ae178b4aGET https://api.github.com/user

The response to this request is — MAGIC! No, it’s the user data. That’s what we wanted all along, right. No need to manage it yourself, just let Github handle it for you.

That was simple enough to understand, wasn’t it? Let’s see how you’d actually implement Github OAuth in your own Golang backend.

Registering a Github OAuth application and initial setup

In your Github account, navigate to Settings > Developer Settings > OAuth Apps, and click on New OAuth App.

New OAuth Application

Then, fill in the necessary details and proceed. Do note that the URL you fill in matters. I will be running my app on localhost:3000 and hence use the below URLs. Still, you can always come back and change this later (as we will do later).

Application details

You should now be able to acquire a Client ID and Client Secret. In the project directory on your computer, create a .env file, and store in it these values in the form below. (P.S. — Do not forget to add .env to your .gitignore file if you intend to push this project to version control later).

CLIENT_ID=xxxxxxxxxxxxxxxxxxxx CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

There we go. We are now set up and ready to code the implementation!

Implementing authentication with a Go backend

Disclaimer before we continue: If you are proceeding to read beyond here, I am hoping you have some basic understanding of how Go code is structured, and the basics of it’s functioning and working principles (like, for example, how Go does not do any JS-like magic for us). Still, even if you don’t, you might want to continue to be able to get a basic gist of how OAuth is actually implemented. I hope my comments and explanations will help you for the same! Let’s start.

Before we continue, let me clarify that I did go back and change the URLs in my GitHub OAuth page to the following:

Inside your project directory run the following command to initialize a go module. This will create a go.mod file, which is something like a Nodejs package.json file.

go mod init github.com/sharmarajdaksh/github-oauth-go

Of course, replace the GitHub username and repo name with your own.

Now, create main.go, and let’s start with the necessary packages and imports. We also define an init() function, which will automatically execute before the main function. Inside it, we will simply load up the environment variables from the .env file we created earlier. If it doesn’t exist, the code panics.

Imports and init

In our main function, we’ll set up our server to listen on port 3000. We define 4 routes: ‘/’, ‘/login/github’, ‘/login/github/callback’, and ‘/loggedin’. Their purpose should be self-explanatory. Let’s see the code.

main( )

Each HandleFunc() call requires a Handler as the second argument. We’ll see their implementation below. Interesting here is the HandleFunc for the ‘/loggedin’ route. We implement it differently simply to allow us to pass data to the handler from elsewhere (as we will later). The actual loggedinHandler is very basic:

loggedinHandler

All we do here is return prettified JSON data which is passed to it from elsewhere if provided. Otherwise, if no data is passed, it returns an unauthorized message.

The rootHandler is even simpler: It merely returns an anchor tag linking to ‘/login/github’.

rootHandler

Before proceeding with the actual implementation of OAuth login, we define two utility functions that simply return the client id and client secret environment variables. As an alternative to this, you may have had these as global variables, and that’s a perfectly acceptable approach.

Utilities

Now, let’s look into our githubLoginHandler which handles the /login/github route.