-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathserver.go
More file actions
104 lines (89 loc) · 2.51 KB
/
server.go
File metadata and controls
104 lines (89 loc) · 2.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package main
import (
"context"
"encoding/json"
"log"
"net/http"
"os"
"golang.org/x/oauth2"
oidc "github.com/coreos/go-oidc"
)
var (
clientID = os.Getenv("GOOGLE_OAUTH2_CLIENT_ID")
clientSecret = os.Getenv("GOOGLE_OAUTH2_CLIENT_SECRET")
)
type Authenticator struct {
provider *oidc.Provider
clientConfig oauth2.Config
ctx context.Context
}
func newAuthenticator() (*Authenticator, error) {
ctx := context.Background()
provider, err := oidc.NewProvider(ctx, "https://accounts.google.com")
if err != nil {
log.Fatalf("failed to get provider: %v", err)
}
config := oauth2.Config{
ClientID: clientID,
ClientSecret: clientSecret,
Endpoint: provider.Endpoint(),
RedirectURL: "http://127.0.0.1:5556/auth/google/callback",
Scopes: []string{oidc.ScopeOpenID, "profile", "email"},
}
return &Authenticator{
provider: provider,
clientConfig: config,
ctx: ctx,
}, nil
}
func (a *Authenticator) handleCallback(w http.ResponseWriter, r *http.Request) {
if r.URL.Query().Get("state") != "state" {
http.Error(w, "state did not match", http.StatusBadRequest)
return
}
token, err := a.clientConfig.Exchange(a.ctx, r.URL.Query().Get("code"))
if err != nil {
log.Printf("no token found: %v", err)
w.WriteHeader(http.StatusUnauthorized)
return
}
rawIDToken, ok := token.Extra("id_token").(string)
if !ok {
http.Error(w, "No id_token field in oauth2 token.", http.StatusInternalServerError)
return
}
oidcConfig := &oidc.Config{
ClientID: clientID,
}
idToken, err := a.provider.Verifier(oidcConfig).Verify(a.ctx, rawIDToken)
if err != nil {
http.Error(w, "Failed to verify ID Token: "+err.Error(), http.StatusInternalServerError)
return
}
resp := struct {
OAuth2Token *oauth2.Token
IDTokenClaims *json.RawMessage
}{token, new(json.RawMessage)}
if err := idToken.Claims(&resp.IDTokenClaims); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
data, err := json.MarshalIndent(resp, "", " ")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Write(data)
}
func main() {
auther, err := newAuthenticator()
if err != nil {
log.Fatalf("failed to get authenticator: %v", err)
}
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, auther.clientConfig.AuthCodeURL("state"), http.StatusFound)
})
mux.HandleFunc("/auth/google/callback", auther.handleCallback)
log.Fatal(http.ListenAndServe("127.0.0.1:5556", mux))
}