Skip to content

Instantly share code, notes, and snippets.

@santosh
Last active September 5, 2020 05:13
Show Gist options
  • Save santosh/4a244d0457390853ba598039f6c119a1 to your computer and use it in GitHub Desktop.
Save santosh/4a244d0457390853ba598039f6c119a1 to your computer and use it in GitHub Desktop.
Webpage OAuth flow example with GitHub.
package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
)
const clientID = "<your client id here>"
const clientSecret = "<your client secret here>"
func main() {
fs := http.FileServer(http.Dir("public"))
http.Handle("/", fs)
// We will be using `httpClient` to make external HTTP requests later in our code
httpClient := http.Client{}
// Create a nwe redirect route route
http.HandleFunc("/oauth/redirect", func(w http.ResponseWriter, r *http.Request) {
// First we neet to get the value of the `code` query param
err := r.ParseForm()
if err != nil {
fmt.Fprintf(os.Stdout, "could not parse query: %v", err)
w.WriteHeader(http.StatusBadRequest)
}
code := r.FormValue("code")
// Next, lets for the HTTP request to call the github oauth endpoint
// to get our access token
reqURL := fmt.Sprintf("https://github.com/login/oauth/access_token?client_id=%s&client_secret=%s&code=%s", clientID, clientSecret, code)
req, err := http.NewRequest(http.MethodPost, reqURL, nil)
if err != nil {
fmt.Fprintf(os.Stdout, "could not create HTTP request: %v", err)
w.WriteHeader(http.StatusBadRequest)
}
// We set this header since we want the response at JSON
req.Header.Set("accept", "application/json")
// Send out the HTTP request
res, err := httpClient.Do(req)
if err != nil {
fmt.Fprintf(os.Stdout, "could not sed HTTP request: %v", err)
w.WriteHeader(http.StatusInternalServerError)
}
defer res.Body.Close()
// Parse the request body into the `OAuthAccessResponse` struct
var t OAuthAccessResponse
if err := json.NewDecoder(res.Body).Decode(&t); err != nil {
fmt.Fprintf(os.Stdout, "could not parse JSON response: %v", err)
w.WriteHeader(http.StatusBadRequest)
}
// Finally, send a response to redicet the user to the welcome page
// with the access token
w.Header().Set("Location", "/welcome.html?access_token="+t.AccessToken)
w.WriteHeader(http.StatusFound)
})
http.ListenAndServe(":8080", nil)
}
type OAuthAccessResponse struct {
AccessToken string `json:"access_token"`
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login with GitHub</title>
</head>
<body>
<a href="https://github.com/login/oauth/authorize?client_id=<your client id here>&redirect_uri=http://localhost:8080/oauth/redirect">Login with GitHub</a>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello</title>
</head>
<body>
</body>
<script>
// We can get the token from the "access_token" query
// param, available in the browesers "location" global
const query = window.location.search.substring(1)
const token = query.split('access_token=')[1]
// Call the user info API using the fetch browser library
fetch('https://api.github.com/user', {
headers: {
// Include the token in the Authorization header
Authorization: 'token ' + token
}
})
// Parse the response as JSON
.then(res => res.json())
.then(res => {
// Once we get the response (which has many fields)
// Documented here: https://developer.github.com/v3/users/#get-the-authenticated-user
// Write "Welcome <user name>" to the documents body
const nameNode = document.createTextNode(`Welcome, ${res.name}`)
document.body.appendChild(nameNode)
})
</script>
</html>
@santosh
Copy link
Author

santosh commented Sep 5, 2020

HTML files are supposed to be in public subdir.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment