-
Notifications
You must be signed in to change notification settings - Fork 0
/
authflow.go
217 lines (197 loc) · 5.64 KB
/
authflow.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
package client
import (
"context"
"net/url"
"os"
)
// AuthFlow contains parameters of OAuth2 flow
type AuthFlow struct {
clientID string
clientSecret string
redirectURI string
username string
password string
scope string
ownerType string
state string
url string
}
// AuthFlowOption provdes parameters for AuthFlow
type AuthFlowOption func(*AuthFlow)
// ResourceOwnerRequest is used to initiate Resource Owner flow
type ResourceOwnerRequest struct {
GrantType string `json:"grant_type"`
ClientID string `json:"client_id"`
Scope string `json:"scope"`
ClientSecret string `json:"client_secret"`
Username string `json:"username"`
Password string `json:"password"`
}
// revive:disable:exported
// ClientCredentialsRequest is used to initiate Client Credentials flow
type ClientCredentialsRequest struct {
GrantType string `json:"grant_type"`
ClientID string `json:"client_id"`
Scope string `json:"scope"`
ClientSecret string `json:"client_secret"`
}
// revive:enable:exported
// AuthCodeRequest is used to initiate Authorization Code flow
type AuthCodeRequest struct {
GrantType string `json:"grant_type"`
ClientID string `json:"client_id"`
Scope string `json:"scope"`
ClientSecret string `json:"client_secret"`
Code string `json:"code"`
RedirectURI string `json:"redirect_uri"`
}
// WithClientID is used to set Client ID for Oauth2 flow
func WithClientID(id string) func(*AuthFlow) {
return func(p *AuthFlow) {
p.clientID = id
}
}
// WithClientSecret is used to set Client Secret for Oauth2 flow
func WithClientSecret(secret string) func(*AuthFlow) {
return func(p *AuthFlow) {
p.clientSecret = secret
}
}
// WithRedirectURI is used to set redirect URI for Oauth2 flow
func WithRedirectURI(uri string) func(*AuthFlow) {
return func(p *AuthFlow) {
p.redirectURI = uri
}
}
// WithUserName is used to set User Name for Oauth2 flow
func WithUserName(username string) func(*AuthFlow) {
return func(p *AuthFlow) {
p.username = username
}
}
// WithPassword is used to set password for Oauth2 flow
func WithPassword(password string) func(*AuthFlow) {
return func(p *AuthFlow) {
p.password = password
}
}
// WithScope is used to set Scope for Oauth2 flow
func WithScope(scope string) func(*AuthFlow) {
return func(p *AuthFlow) {
p.scope = scope
}
}
// WithState is used to set State for Oauth2 flow
func WithState(state string) func(*AuthFlow) {
return func(p *AuthFlow) {
p.state = state
}
}
// WithOwnerType is used to set Owner Type for Oauth2 flow
func WithOwnerType(ownerType string) func(*AuthFlow) {
return func(p *AuthFlow) {
p.ownerType = ownerType
}
}
// NewAuthFlow returns a AuthFlow
func NewAuthFlow(url string, params ...AuthFlowOption) *AuthFlow {
flow := AuthFlow{
scope: "profile",
ownerType: "user",
url: url,
}
flow.clientID, _ = os.LookupEnv("ONECRM_CLIENT_ID")
flow.clientSecret, _ = os.LookupEnv("ONECRM_CLIENT_SECRET")
flow.redirectURI, _ = os.LookupEnv("ONECRM_REDIRECT_URI")
flow.username, _ = os.LookupEnv("ONECRM_USERNAME")
flow.password, _ = os.LookupEnv("ONECRM_PASSWORD")
for _, p := range params {
p(&flow)
}
return &flow
}
// InitAuthCode is used to initiate Authorization Code flow.
// It returns an URL the user is to be redirected to in order to complete the flow.
func (flow *AuthFlow) InitAuthCode() (string, error) {
u, err := url.Parse(flow.url + "/auth/" + flow.ownerType + "/authorize")
if err != nil {
return "", err
}
values := make(url.Values)
values.Set("response_type", "code")
values.Set("client_id", flow.clientID)
values.Set("redirect_uri", flow.redirectURI)
values.Set("state", flow.state)
u.RawQuery = values.Encode()
return u.String(), nil
}
// FinalizeAuthCode completes the Authorization Code flow and returns an access token
func (flow *AuthFlow) FinalizeAuthCode(ctx context.Context, code string) (*OAuth2AccessToken, error) {
body := AuthCodeRequest{
GrantType: "authorization_code",
ClientID: flow.clientID,
ClientSecret: flow.clientSecret,
Scope: flow.scope,
RedirectURI: flow.redirectURI,
Code: code,
}
c := NewClient(ctx, flow.url, nil)
res, err := c.Post(
"auth/"+flow.ownerType+"/access_token",
WithJSONBody(body),
)
if err != nil {
return nil, err
}
var token OAuth2AccessToken
if err = res.ParseJSON(&token); err != nil {
return nil, err
}
return &token, nil
}
// InitResourceOwner returns an access token for resource owner (user or contact)
func (flow *AuthFlow) InitResourceOwner(ctx context.Context) (*OAuth2AccessToken, error) {
body := ResourceOwnerRequest{
GrantType: "password",
ClientID: flow.clientID,
ClientSecret: flow.clientSecret,
Scope: flow.scope,
Username: flow.username,
Password: flow.password,
}
c := NewClient(ctx, flow.url, nil)
res, err := c.Post(
"auth/"+flow.ownerType+"/access_token",
WithJSONBody(body),
)
if err != nil {
return nil, err
}
var token OAuth2AccessToken
if err = res.ParseJSON(&token); err != nil {
return nil, err
}
return &token, nil
}
// InitClientCredentials returns an access token using the client credentials
func (flow *AuthFlow) InitClientCredentials(ctx context.Context) (*OAuth2AccessToken, error) {
body := ClientCredentialsRequest{
GrantType: "client_credentials",
ClientID: flow.clientID,
ClientSecret: flow.clientSecret,
Scope: flow.scope,
}
c := NewClient(ctx, flow.url, nil)
res, err := c.Post(
"auth/"+flow.ownerType+"/access_token",
WithJSONBody(body),
)
if err != nil {
return nil, err
}
var token OAuth2AccessToken
if err = res.ParseJSON(&token); err != nil {
return nil, err
}
return &token, nil
}