Skip to content

Instantly share code, notes, and snippets.

@neverlock
Last active February 15, 2021 00:42
Show Gist options
  • Save neverlock/62aa6b4647203cea5cbd5dc541ff7203 to your computer and use it in GitHub Desktop.
Save neverlock/62aa6b4647203cea5cbd5dc541ff7203 to your computer and use it in GitHub Desktop.
example oauth-google

from https://dev.to/douglasmakey/oauth2-example-with-go-3n8a

example of "enable API" button https://cloud.google.com/resource-manager/docs/creating-managing-projects#api_1

example of "enable API" button https://cloud.google.com/resource-manager/reference/rest/v1/projects/create?hl=th

oauth 2 client https://cloud.google.com/docs/authentication#oauth-2.0-clients

oauth 2 webserver https://developers.google.com/identity/protocols/oauth2/web-server?hl=th

link for create Start project & set credential type

https://console.developers.google.com/henhouse/?pb=%5B%22hh-0%22,%22drive%22,null,%5B%5D,%22https:%2F%2Fdevelopers.google.com%22,null,%5B%5D,null,%22Enable%20the%20Drive%20API%22,1,null,%5B%5D,false,false,null,null,null,null,false,null,false,false,null,null,null,%22DESKTOP%22,null,%22Quickstart%22,true,%22Quickstart%22,null,null,false%5D

https://console.developers.google.com/henhouse/?pb=%5B%22hh-0%22,%22drive%22,null,%5B%5D,%22https:%2F%2Fdevelopers.google.com%22,null,%5B%5D,null,%22Enable%20the%20Drive%20API%22,1,null,%5B%5D,false,false,null,null,null,null,false,null,false,false,null,null,null,%22WEB_SERVER%22,null,%22Quickstart%22,true,%22Quickstart%22,null,null,false%5D

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)
return mux
}
package main
import (
"fmt"
"net/http"
"log"
"github.com/douglasmakey/oauth2-example/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!")
}
}
package handlers
import (
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"net/http"
"fmt"
"io/ioutil"
"context"
"log"
"encoding/base64"
"crypto/rand"
"os"
"time"
)
// Scopes: OAuth 2.0 scopes provide a way to limit the amount of access that is granted to an access token.
// for drive access scope = https://www.googleapis.com/auth/drive.file
// list of all scope = https://developers.google.com/identity/protocols/oauth2/scopes#drive
var googleOauthConfig = &oauth2.Config{
RedirectURL: "http://localhost:8000/auth/google/callback",
ClientID: os.Getenv("GOOGLE_OAUTH_CLIENT_ID"),
ClientSecret: os.Getenv("GOOGLE_OAUTH_CLIENT_SECRET"),
Scopes: []string{"https://www.googleapis.com/auth/userinfo.email"},
Endpoint: google.Endpoint,
}
const oauthGoogleUrlAPI = "https://www.googleapis.com/oauth2/v2/userinfo?access_token="
func oauthGoogleLogin(w http.ResponseWriter, r *http.Request) {
// Create oauthState cookie
oauthState := generateStateOauthCookie(w)
/*
AuthCodeURL receive state that is a token to protect the user from CSRF attacks. You must always provide a non-empty string and
validate that it matches the the state query parameter on your redirect callback.
*/
u := googleOauthConfig.AuthCodeURL(oauthState)
http.Redirect(w, r, u, http.StatusTemporaryRedirect)
}
func oauthGoogleCallback(w http.ResponseWriter, r *http.Request) {
// Read oauthState from Cookie
oauthState, _ := r.Cookie("oauthstate")
if r.FormValue("state") != oauthState.Value {
log.Println("invalid oauth google state")
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
data, err := getUserDataFromGoogle(r.FormValue("code"))
if err != nil {
log.Println(err.Error())
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
return
}
// GetOrCreate User in your db.
// Redirect or response with a token.
// More code .....
fmt.Fprintf(w, "UserInfo: %s\n", data)
}
func generateStateOauthCookie(w http.ResponseWriter) string {
var expiration = time.Now().Add(365 * 24 * time.Hour)
b := make([]byte, 16)
rand.Read(b)
state := base64.URLEncoding.EncodeToString(b)
cookie := http.Cookie{Name: "oauthstate", Value: state, Expires: expiration}
http.SetCookie(w, &cookie)
return state
}
func getUserDataFromGoogle(code string) ([]byte, error) {
// Use code to get token and get user info from Google.
token, err := googleOauthConfig.Exchange(context.Background(), code)
if err != nil {
return nil, fmt.Errorf("code exchange wrong: %s", err.Error())
}
response, err := http.Get(oauthGoogleUrlAPI + token.AccessToken)
if err != nil {
return nil, fmt.Errorf("failed getting user info: %s", err.Error())
}
defer response.Body.Close()
contents, err := ioutil.ReadAll(response.Body)
if err != nil {
return nil, fmt.Errorf("failed read response: %s", err.Error())
}
return contents, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment