Last active
April 11, 2024 16:15
-
-
Save hnaohiro/1473e31ea9317f6c03f18ec12a3c949a to your computer and use it in GitHub Desktop.
Sample code Go, OAuth, Google
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/json" | |
"io" | |
"log" | |
"log/slog" | |
"net/http" | |
"os" | |
"time" | |
"github.com/gorilla/mux" | |
"github.com/gorilla/sessions" | |
"golang.org/x/oauth2" | |
"golang.org/x/oauth2/google" | |
) | |
func main() { | |
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) | |
slog.SetDefault(logger) | |
r := mux.NewRouter() | |
r.HandleFunc("/", indexHandler).Methods(http.MethodGet) | |
r.HandleFunc("/auth/callback/google", authGoogleCallbackHandler).Methods(http.MethodGet) | |
srv := &http.Server{ | |
Addr: ":8080", | |
Handler: r, | |
ReadHeaderTimeout: 30 * time.Second, | |
} | |
if err := srv.ListenAndServe(); err != nil { | |
log.Fatal(err) | |
} | |
} | |
func newConf() (*oauth2.Config, error) { | |
credentialsJSON := []byte(os.Getenv("GOOGLE_CREDENTIALS_JSON")) | |
scope := "https://www.googleapis.com/auth/userinfo.email" | |
return google.ConfigFromJSON(credentialsJSON, scope) | |
} | |
var ( | |
key = []byte("orchestration-gateway-google-auth-test") | |
store = sessions.NewCookieStore(key) | |
) | |
func indexHandler(w http.ResponseWriter, r *http.Request) { | |
conf, err := newConf() | |
if err != nil { | |
slog.Error("indexHandler, newConf", err) | |
w.WriteHeader(http.StatusInternalServerError) | |
return | |
} | |
session, err := store.Get(r, "auth") | |
if err != nil { | |
slog.Error("indexHandler, store Get", err) | |
w.WriteHeader(http.StatusInternalServerError) | |
return | |
} | |
email := session.Values["email"] | |
if email != nil { | |
w.WriteHeader(http.StatusOK) | |
_, _ = w.Write([]byte("Hello, " + email.(string) + "!")) | |
return | |
} | |
state := os.Getenv("OAUTH_STATE") | |
session.Values["state"] = state | |
if err = session.Save(r, w); err != nil { | |
slog.Error("indexHandler, store Save", err) | |
w.WriteHeader(http.StatusInternalServerError) | |
return | |
} | |
redirectURL := conf.AuthCodeURL(state, oauth2.AccessTypeOnline, oauth2.ApprovalForce) | |
http.Redirect(w, r, redirectURL, http.StatusSeeOther) | |
} | |
func authGoogleCallbackHandler(w http.ResponseWriter, r *http.Request) { | |
session, err := store.Get(r, "auth") | |
if err != nil { | |
slog.Error("authGoogleCallbackHandler, store Get", err) | |
w.WriteHeader(http.StatusInternalServerError) | |
return | |
} | |
state := session.Values["state"] | |
if state != r.URL.Query().Get("state") { | |
slog.Error("authGoogleCallbackHandler, state mismatch", err) | |
w.WriteHeader(http.StatusInternalServerError) | |
return | |
} | |
conf, err := newConf() | |
if err != nil { | |
slog.Error("authGoogleCallbackHandler, newConf", err) | |
w.WriteHeader(http.StatusInternalServerError) | |
return | |
} | |
token, err := conf.Exchange(r.Context(), r.URL.Query().Get("code")) | |
if err != nil { | |
slog.Error("authGoogleCallbackHandler, conf Exchange", err) | |
w.WriteHeader(http.StatusInternalServerError) | |
return | |
} | |
client := conf.Client(r.Context(), token) | |
response, err := client.Get("https://www.googleapis.com/oauth2/v2/userinfo") | |
if err != nil { | |
slog.Error("authGoogleCallbackHandler, client Get", err) | |
w.WriteHeader(http.StatusInternalServerError) | |
return | |
} | |
defer func() { | |
_ = response.Body.Close() | |
}() | |
if response.StatusCode != http.StatusOK { | |
slog.Error("authGoogleCallbackHandler, response StatusCode", slog.Int("value", response.StatusCode)) | |
w.WriteHeader(http.StatusInternalServerError) | |
return | |
} | |
body, err := io.ReadAll(response.Body) | |
if err != nil { | |
slog.Error("authGoogleCallbackHandler, io ReadAll", err) | |
w.WriteHeader(http.StatusInternalServerError) | |
return | |
} | |
var payload map[string]any | |
if err := json.Unmarshal(body, &payload); err != nil { | |
slog.Error("authGoogleCallbackHandler, json Unmarshal", err) | |
w.WriteHeader(http.StatusInternalServerError) | |
return | |
} | |
email, ok := payload["email"].(string) | |
if !ok { | |
slog.Error("authGoogleCallbackHandler, payload email", err) | |
w.WriteHeader(http.StatusInternalServerError) | |
return | |
} | |
session.Values["email"] = email | |
if err = session.Save(r, w); err != nil { | |
slog.Error("authGoogleCallbackHandler, store Save", err) | |
w.WriteHeader(http.StatusInternalServerError) | |
return | |
} | |
http.Redirect(w, r, "/", http.StatusSeeOther) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment