-
Notifications
You must be signed in to change notification settings - Fork 0
/
oauth2.go
100 lines (87 loc) · 3.29 KB
/
oauth2.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
package facebook
import (
"net/http"
"github.com/Lambels/autho"
autho2 "github.com/Lambels/autho/oauth2"
fb "github.com/huandu/facebook/v2"
"golang.org/x/oauth2"
)
// NewCallbackHandler is a helper function that constructs
// a new callback handler using the default token handler facebook.NewTokenHandler()
// wrapped arround the default facebook.NewUserHandler().
//
// This method saves allot of boilerplate. For more customisable handlers construct your
// own callback handler by wrapping your own specific token handler around your own specific user handler.
func NewCallbackHandler(cfg *oauth2.Config, ckCfg *autho.CookieConfig, errHandler, terminalHandler http.Handler) http.Handler {
return NewTokenHandler(
cfg,
ckCfg,
errHandler,
NewUserHandler(
cfg,
errHandler,
terminalHandler,
),
)
}
// NewLoginHandler creates a new LoginHandler which is resposible for setting a random
// value (state) to the state cookie. Afterwards the login handler is also
// responsible for redirecting the user to the provider for the users grant.
func NewLoginHandler(cfg *oauth2.Config, ckCfg *autho.CookieConfig) http.Handler {
return autho2.NewLoginHandler(cfg, ckCfg)
}
// NewTokenHandler creates a new TokenHandler which is the first handler in the chain responding
// to the callback from the provider, it is responsible for parsing the response for auth code
// and state then comparing the cookie state with the request state. Following the parsing the
// TokenHandler performs the token exchange and adds the token to the request context, calling on
// success the UserHandler.
func NewTokenHandler(cfg *oauth2.Config, ckCfg *autho.CookieConfig, errHandler, userHandler http.Handler) http.Handler {
return autho2.NewTokenHandler(cfg, ckCfg, errHandler, userHandler)
}
// NewUserHandler creates a new facebook UserHandler resposnible for using the tokens provided
// by the TokenHandler in exchange for the users resource. The user resource is set under the
// request context.
//
// user, ok := autho.UserFromContext(r.Context()).(*facebook.User)
//
// The UserModel used by default by the facebook.NewUserHandler is: https://developers.facebook.com/docs/graph-api/reference/user/#default-public-profile-fields
func NewUserHandler(cfg *oauth2.Config, errHandler, terminalHandler http.Handler) http.Handler {
if errHandler == nil {
errHandler = autho.DefaultFailureHandle
}
f := func(w http.ResponseWriter, r *http.Request) {
tkn, err := autho2.TokenFromContext(r.Context())
if err != nil {
autho.PassError(err, errHandler, w, r)
return
}
httpClient := cfg.Client(r.Context(), tkn)
session := &fb.Session{
Version: "v2.4",
HttpClient: httpClient,
}
res, err := session.Get("/me", nil)
if err != nil {
// facebook api error.
if e, ok := err.(*fb.Error); ok {
autho.PassError(e, errHandler, w, r)
return
}
// facebook unmarshal error.
if e, ok := err.(*fb.UnmarshalError); ok {
autho.PassError(e, errHandler, w, r)
return
}
autho.PassError(autho.ErrNoUser, errHandler, w, r)
return
}
var user User
if err := res.Decode(&user); err != nil {
autho.PassError(autho.ErrNoUser, errHandler, w, r)
return
}
userCtx := autho.ContextWithUser(r.Context(), &user)
terminalHandler.ServeHTTP(w, r.WithContext(userCtx))
}
return http.HandlerFunc(f)
}