Skip to content

Instantly share code, notes, and snippets.

@9nut
Created November 1, 2014 07:46
Show Gist options
  • Save 9nut/1f883d857369a279f289 to your computer and use it in GitHub Desktop.
Save 9nut/1f883d857369a279f289 to your computer and use it in GitHub Desktop.
Sample Go Web Server that handles OAuth2 authentication through Google.
package main
import (
"code.google.com/p/goauth2/oauth"
"crypto/tls"
"encoding/json"
"flag"
"io/ioutil"
"log"
"net/http"
"strings"
"text/template"
)
var notAuthenticatedTemplate = template.Must(template.New("").Parse(`
<html><body>
Please authenticate this app with the Google OAuth provider.
<form action="/authorize" method="POST"><input type="submit" value="Ok, authorize this app with my id"/></form>
</body></html>
`))
var userInfoTemplate = template.Must(template.New("").Parse(`
<html><body>
This app is now authenticated to access your Google user info. Your details are:<br />
{{.}}
</body></html>
`))
// variables used during oauth protocol flow of authentication
var (
code = ""
token = ""
)
type KeyEnv struct {
AKey AppKey `json:"web"`
}
type AppKey struct {
ClientId string `json:"client_id"`
ClientSecret string `json:"client_secret"`
ClientEmail string `json:"client_email"`
AuthURL string `json:"auth_uri"`
TokenURL string `json:"token_uri"`
RedirectURLs []string `json:"redirect_uris"`
ProviderX509 string `json:"auth_provider_x509_cert_url"`
JSOrigins []string `json:"javascript_origins"`
}
var oauthCfg *oauth.Config
var (
hostport = flag.String("http", ":443", "host:port")
clisec = flag.String("secret", "client_secrets.json", "client secrets JSON file")
)
//This is the URL that Google has defined so that an authenticated application may obtain the user's info in json format
const profileInfoURL = "https://www.googleapis.com/oauth2/v2/userinfo"
func main() {
var k KeyEnv
flag.Parse()
appkey, err := ioutil.ReadFile(*clisec)
if err != nil {
log.Fatal(err)
}
dec := json.NewDecoder(strings.NewReader(string(appkey)))
if err = dec.Decode(&k); err != nil {
log.Fatal(err)
}
oauthCfg = &oauth.Config{
ClientId: k.AKey.ClientId,
ClientSecret: k.AKey.ClientSecret,
AuthURL: k.AKey.AuthURL,
TokenURL: k.AKey.TokenURL,
RedirectURL: k.AKey.RedirectURLs[0],
Scope: "https://www.googleapis.com/auth/userinfo.email",
}
http.HandleFunc("/", handleRoot)
http.HandleFunc("/authorize", handleAuthorize)
//Google will redirect to this page to return your code, so handle it appropriately
http.HandleFunc("/oauth2callback", handleOAuth2Callback)
log.Println("Listen On: " + *hostport)
http.ListenAndServeTLS(*hostport, "cert.pem", "key.pem", nil)
}
func handleRoot(w http.ResponseWriter, r *http.Request) {
notAuthenticatedTemplate.Execute(w, nil)
}
// Start the authorization process
func handleAuthorize(w http.ResponseWriter, r *http.Request) {
//Get the Google URL which shows the Authentication page to the user
url := oauthCfg.AuthCodeURL("")
//redirect user to that page
http.Redirect(w, r, url, http.StatusFound)
}
// Function that handles the callback from the Google server
func handleOAuth2Callback(w http.ResponseWriter, r *http.Request) {
//Get the code from the response
code := r.FormValue("code")
t := &oauth.Transport{Config: oauthCfg}
// Exchange the received code for a token
tok, err := t.Exchange(code)
if err != nil {
log.Printf("Error exchanging token: %v", err)
http.Redirect(w, r, "/", http.StatusFound)
return
}
tokenCache := oauth.CacheFile("./request.token")
err = tokenCache.PutToken(tok)
if err != nil {
log.Fatal("Cache write:", err)
}
log.Printf("Token is cached in %v\n", tokenCache)
// Skip TLS Verify
t.Transport = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
// Make the request.
req, err := t.Client().Get(profileInfoURL)
if err != nil {
log.Fatal("Request Error:", err)
}
defer req.Body.Close()
body, err := ioutil.ReadAll(req.Body)
if err != nil {
log.Fatal(err)
}
log.Println(string(body))
userInfoTemplate.Execute(w, string(body))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment