Main navigation

Authenticating with Google OAuth 2.0 - Part I

This is a two part post which explains, with samples, how to do authorization for a web site using Google Authentication OAuth 2.0 services. The first part introduces necessary steps to get started using the Go client provided by Google, and how to setup your application with Google in order to use the API, to retrieve information about the user.

Setup

Google OAuth token

First things first, you need to register your application with Google, so you’ll get a Token that you can use to authorize later calls to Google services. You can do that here: Google Developer Console. You’ll have to create a new project. Once that’s done, click on Credentials and create an OAuth token. You should see this message: “To create an OAuth client ID, you must first set a product name on the consent screen.”. Go through the questions, like, what type of application you have, and once you arrive at the stage where it asks for your application’s name – there is a section asking for a redirect URL; there, write the url you wish to use when authorizing your user. If you don’t know this yet, don’t fret, we can come back and change it later. Do NOT use localhost. If you are running your application on your own machine, use http://127.0.0.1:port/whatever.

This will get you a client ID and a client secret. I’m going to save these into a file which will sit next to my web app. It could be stored more securely, for example, in a database or a mounted secure, encrypted drive, but that’s not the point of this tutorial. Your application can now be identified through Google services.

The Application

Library

Google has a nice library to use with OAuth 2.0. The library is available here: Google OAuth 2.0. It’s a bit cryptic at first to set-up, but not to worry. After a bit of fiddling you’ll quickly understand what it does. I’m also using Gin, and Gin’s session handling middleware Gin-Session.

Setup - Credentials

Let’s create a setup which configures our credentials from the file we saved earlier. This is pretty straightforward.

Once you have the creds loaded, you can go on to construct the OAuth client.

Setup - OAuth client

Construct the OAuth config:

conf := &oauth2.Config{

ClientID: c.Cid,

ClientSecret: c.Csecret,

RedirectURL:"http://localhost:9090/auth",

Scopes:[]string{

"https://www.googleapis.com/auth/userinfo.email",// You have to select your own scope from here -> https://developers.google.com/identity/protocols/googlescopes#google_sign-in

},

Endpoint: google.Endpoint,

}

It will give you a conf struct, which you can then use to Authorize the user in the Google domain. Next, all we need to do is call AuthCodeURL on this config. It will give you a URL which redirects to a Google Sign-In form. Once the user fills that out and clicks ‘Allow’, you’ll get back a TOKEN in the code query parameter and a state which helps protect against CSRF attacks. Always check if the provided state is what you provided with AuthCodeURL. The url will be something like this: http://127.0.0.1:9090/auth?code=4FLKFskdjflf3343d4f&state=lhfu3f983j;asdf. Small function to call AuthCodeURL:

func getLoginURL(state string)string{

// State can be some random generated hash string.

// See relevant RFC: http://tools.ietf.org/html/rfc6749#section-10.12

return conf.AuthCodeURL(state)

}

Construct a button which the user can click and be redirected to the Google Sign-In form. When constructing the url, you must do one more thing. Create a secure state token and save it in the form of a cookie for the current user.

Parse it, and you’ll get an email which you can store somewhere for registration purposes. At this point, your user is not yet Authenticated. My next post will explain how to retrieve the stored email address, and also explain user session handling with Gin and MongoDB.

Putting it all together

The full source code (excluding the templates):

package main

import(

"crypto/rand"

"encoding/base64"

"encoding/json"

"io/ioutil"

"fmt"

"log"

"os"

"net/http"

"github.com/gin-gonic/contrib/sessions"

"github.com/gin-gonic/gin"

"golang.org/x/oauth2"

"golang.org/x/oauth2/google"

)

// Credentials which store google ids.

type Credentials struct{

Cid string`json:"cid"`

Csecret string`json:"csecret"`

}

// User is a retrieved and authentiacted user.

type User struct{

Sub string`json:"sub"`

Name string`json:"name"`

GivenName string`json:"given_name"`

FamilyName string`json:"family_name"`

Profile string`json:"profile"`

Picture string`json:"picture"`

Email string`json:"email"`

EmailVerified string`json:"email_verified"`

Gender string`json:"gender"`

}

var cred Credentials

var conf *oauth2.Config

var state string

var store = sessions.NewCookieStore([]byte("secret"))

func randToken()string{

b :=make([]byte,32)

rand.Read(b)

return base64.StdEncoding.EncodeToString(b)

}

func init(){

file, err := ioutil.ReadFile("./creds.json")

if err !=nil{

log.Printf("File error: %v\n", err)

os.Exit(1)

}

json.Unmarshal(file, &cred)

conf = &oauth2.Config{

ClientID: cred.Cid,

ClientSecret: cred.Csecret,

RedirectURL:"http://127.0.0.1:9090/auth",

Scopes:[]string{

"https://www.googleapis.com/auth/userinfo.email",// You have to select your own scope from here -> https://developers.google.com/identity/protocols/googlescopes#google_sign-in