Reference

Go Reference - Http "net/http"

Go Reference - OAuth2 for Go "golang.org/x/oauth2"

Go Reference - OAuth2 (Google APIs) "golang.org/x/oauth2/google"

Authorization Server Flow

Diagram of OAuth authorization flow

  1. A Go client will serve a redirect to a browser. This redirect will include a random state variable and a following redirect URL back to the Go client from the authorizing server.
  2. The user enters credentials into the browser (user agent).
  3. The user agent send credentials to the authorization server (u := config.AuthCodeURL(oauthState) prepares the URL, a call to http.Redirect() accepts u and the server redirects the browser)
  4. Authorization server returns an authorization code (r.FormValue("code"))
  5. The Go client will exchange the authorization code for an access token (the client will store the access token in a cookie).
  6. The Go client uses the access token to access scoped resource servers.

A Simple OAuth Implementation

Download the oauth2 library for import.

go get golang.org/x/oauth2

The app structure I followed is pretty simple:

1. In main.go use net/http to start a server

main.go

package main

import (
"fmt"
"log"
"net/http"

"foundry-automations/handlers"
)

func main() {
server := &http.Server{
    Addr:    fmt.Sprintf(":8000"),
    Handler: handlers.New(),
}

log.Printf("Starting HTTP Server. Listening at %q", server.Addr)
if err := server.ListenAndServe(); err != http.ErrServerClosed {
    log.Printf("%v", err)
  } else {
    log.Println("Server closed!")
  }
}

2. Create a module /handlers and add two .go files

  • base.go
  • <service>.go where <service> is a meaningful representation of the authorization server you are relying on (e.g., google apis)

3. Create a Handler

In base.go create func New() http.Handler {} and set up a mux with two handlers, "/auth/<service>/login" and "/auth/<service>/callback", then return mux. The helper functions passed as the second argument of mux.HandleFunc will live in your <service>.go implementation

base.go

package handlers

import (
{
    "net/http"
)

func New() http.Handler {
mux := http.NewServeMux()
// Root
mux.Handle("/", http.FileServer(http.Dir("templates/")))

// // OauthGoogle
// mux.HandleFunc("/auth/google/login", oauthGoogleLogin)
// mux.HandleFunc("/auth/google/callback", oauthGoogleCallback)
mux.HandleFunc("/auth/pco/login", pcoLogin)
mux.HandleFunc("/auth/pco/callback", pcoCallback)

return mux
  }
}

Michael Lamb is a software engineer for privately-held telecommunications and technology company C Spire, headquartered in Ridgeland, Mississippi. He is a resident of Jackson, Mississippi, with his two cats and many plants. He graduated from Mississippi State University with a bachelor of science in Software Engineering. He is happily employed full-time creating microservices using Java and Spring technologies but is open to consulting.
© Copyright 2021