generated from matoszz/mitbgo-template
-
Notifications
You must be signed in to change notification settings - Fork 7
/
main.go
135 lines (121 loc) · 4.08 KB
/
main.go
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package main
import (
"flag"
"fmt"
"log"
"net/http"
"os"
"golang.org/x/oauth2"
githubOAuth2 "golang.org/x/oauth2/github"
"github.com/datumforge/datum/pkg/providers/github"
"github.com/datumforge/datum/pkg/sessions"
)
const (
sessionName = "example-github-app"
sessionSecret = "example cookie signing secret"
sessionUserKey = "githubID"
sessionUsername = "githubUsername"
)
// sessionStore encodes and decodes session data stored in signed cookies
var sessionStore = sessions.NewCookieStore[any](sessions.DebugCookieConfig, []byte(sessionSecret), nil)
// Config configures the main ServeMux.
type Config struct {
ClientID string
ClientSecret string
}
var DebugOnlyCookieConfig = sessions.CookieConfig{
Name: "temporary-cookie",
Path: "/",
MaxAge: 600, // 10 min
HTTPOnly: true,
Secure: false, // allows cookies to be send over HTTP
SameSite: http.SameSiteLaxMode,
}
// New returns a new ServeMux with app routes.
func New(config *Config) *http.ServeMux {
mux := http.NewServeMux()
mux.HandleFunc("/", profileHandler)
mux.HandleFunc("/logout", logoutHandler)
// 1. Register LoginHandler and CallbackHandler
oauth2Config := &oauth2.Config{
ClientID: config.ClientID,
ClientSecret: config.ClientSecret,
RedirectURL: "http://localhost:8000/v1/github/callback",
Endpoint: githubOAuth2.Endpoint,
}
// state param cookies require HTTPS by default; disable for localhost development
stateConfig := DebugOnlyCookieConfig
mux.Handle("/v1/github/login", github.StateHandler(stateConfig, github.LoginHandler(oauth2Config, nil)))
mux.Handle("/v1/github/callback", github.StateHandler(stateConfig, github.CallbackHandler(oauth2Config, issueSession(), nil)))
return mux
}
// issueSession issues a cookie session after successful GitHub login
func issueSession() http.Handler {
fn := func(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
githubUser, err := github.UserFromContext(ctx)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// 2. Implement a success handler to issue some form of session
session := sessionStore.New(sessionName)
session.Set(sessionUserKey, *githubUser.ID)
session.Set(sessionUsername, *githubUser.Login)
if err := session.Save(w); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, req, "/profile", http.StatusFound)
}
return http.HandlerFunc(fn)
}
// profileHandler shows a personal profile or a login button (unauthenticated).
func profileHandler(w http.ResponseWriter, req *http.Request) {
session, err := sessionStore.Get(req, sessionName)
if err != nil {
// welcome with login button
page, _ := os.ReadFile("home.html")
fmt.Fprint(w, string(page))
return
}
// authenticated profile
fmt.Fprintf(w, `<p>You are logged in %s!</p><form action="/logout" method="post"><input type="submit" value="Logout"></form>`, session.Get(sessionUsername))
}
// logoutHandler destroys the session on POSTs and redirects to home.
func logoutHandler(w http.ResponseWriter, req *http.Request) {
if req.Method == http.MethodPost {
sessionStore.Destroy(w, sessionName)
}
http.Redirect(w, req, "/", http.StatusFound)
}
// main creates and starts a Server listening.
func main() {
const address = "localhost:8000"
// read credentials from environment variables if available
config := &Config{
ClientID: os.Getenv("GITHUB_CLIENT_ID"),
ClientSecret: os.Getenv("GITHUB_CLIENT_SECRET"),
}
// allow consumer credential flags to override config fields
clientID := flag.String("client-id", "", "GitHub Client ID")
clientSecret := flag.String("client-secret", "", "GitHub Client Secret")
flag.Parse()
if *clientID != "" {
config.ClientID = *clientID
}
if *clientSecret != "" {
config.ClientSecret = *clientSecret
}
if config.ClientID == "" {
log.Fatal("Missing GitHub Client ID")
}
if config.ClientSecret == "" {
log.Fatal("Missing GitHub Client Secret")
}
log.Printf("Starting Server listening on %s\n", address)
err := http.ListenAndServe(address, New(config))
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}