-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
authentication.go
175 lines (155 loc) · 4.97 KB
/
authentication.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
package dotwallet
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
"time"
)
// UpdateApplicationAccessToken will update the application access token
// This will also store the token on the client for easy access (c.options.token)
//
// For more information: https://developers.dotwallet.com/documents/en/#application-authorization
func (c *Client) UpdateApplicationAccessToken() error {
// Make the request
response, err := c.Request(
http.MethodPost,
getAccessTokenURI,
&getAccessTokenRequest{
ClientID: c.options.clientID,
GrantType: grantTypeClientCredentials,
ClientSecret: c.options.clientSecret,
},
http.StatusOK,
nil,
)
if err != nil {
return err
}
// Unmarshal the response
resp := new(accessTokenResponse)
if err = json.Unmarshal(
response.Body, &resp,
); err != nil {
return err
}
// Error?
if resp.Code > 0 {
return fmt.Errorf(resp.Message)
}
// Set the token (access token has limited fields vs user token)
c.options.token = &DotAccessToken{
AccessToken: resp.Data.AccessToken,
ExpiresAt: time.Now().UTC().Unix() + resp.Data.ExpiresIn,
ExpiresIn: resp.Data.ExpiresIn,
TokenType: resp.Data.TokenType,
}
return nil
}
// GetUserToken will get the user's access_token for the first time given the "code" from the oauth2 callback
// This will also store the user's token on the client for easy access (c.options.userToken)
//
// For more information: https://developers.dotwallet.com/documents/en/#user-authorization
func (c *Client) GetUserToken(code string) (*DotAccessToken, error) {
// Make the request
response, err := c.Request(
http.MethodPost,
getAccessTokenURI,
&getDotUserTokenRequest{
getAccessTokenRequest: getAccessTokenRequest{
ClientID: c.options.clientID,
ClientSecret: c.options.clientSecret,
GrantType: grantTypeAuthorizationCode,
},
Code: code,
RedirectURI: c.options.redirectURI,
},
http.StatusOK,
nil,
)
if err != nil {
return nil, err
}
// Unmarshal the response
tokenResponse := new(accessTokenResponse)
if err = json.Unmarshal(
response.Body, &tokenResponse,
); err != nil {
return nil, err
}
// Error?
if tokenResponse.Code > 0 {
return nil, fmt.Errorf(tokenResponse.Message)
}
// Set the user token on the client for easy access
return newUserAccessToken(tokenResponse), nil
}
// RefreshUserToken will refresh the user's auth_token using the refresh_token
// This will also store the user's token on the client for easy access (c.options.userToken)
//
// For more information: https://developers.dotwallet.com/documents/en/#user-authorization
func (c *Client) RefreshUserToken(token *DotAccessToken) (*DotAccessToken, error) {
// Make the request
response, err := c.Request(
http.MethodPost,
getAccessTokenURI,
&refreshDotUserTokenRequest{
getAccessTokenRequest: getAccessTokenRequest{
ClientID: c.options.clientID,
ClientSecret: c.options.clientSecret,
GrantType: grantTypeRefreshToken,
},
RefreshToken: token.RefreshToken,
},
http.StatusOK,
nil,
)
if err != nil {
return nil, err
}
// Unmarshal the response
tokenResponse := new(accessTokenResponse)
if err = json.Unmarshal(
response.Body, &tokenResponse,
); err != nil {
return nil, err
}
// Error?
if tokenResponse.Code > 0 {
token.RefreshToken = ""
return nil, fmt.Errorf(tokenResponse.Message)
}
// Set the user token on the client for easy access
return newUserAccessToken(tokenResponse), nil
}
// GetAuthorizeURL will return a new url for starting the user oauth2 authorization process
//
// For more information: https://developers.dotwallet.com/documents/en/#user-authorization
func (c *Client) GetAuthorizeURL(state string, scopes []string) string {
urlValues := &url.Values{}
urlValues.Add("client_id", c.options.clientID)
urlValues.Add("redirect_uri", c.options.redirectURI)
urlValues.Add("response_type", "code")
urlValues.Add("scope", strings.Join(scopes, " "))
urlValues.Add("state", state)
return fmt.Sprintf("%s%s?%s", c.options.host, authorizeURI, urlValues.Encode())
}
// IsTokenExpired will check if the token is expired
func (c *Client) IsTokenExpired(token *DotAccessToken) bool {
return token.ExpiresAt < time.Now().UTC().Unix()
}
// newUserAccessToken will create the DotAccessToken object which is enriched from the response data
// This is used only for user access_tokens
func newUserAccessToken(tokenResponse *accessTokenResponse) *DotAccessToken {
return &DotAccessToken{
AccessToken: tokenResponse.Data.AccessToken,
ExpiresAt: time.Now().UTC().Unix() + tokenResponse.Data.ExpiresIn,
ExpiresIn: tokenResponse.Data.ExpiresIn,
RefreshToken: tokenResponse.Data.RefreshToken,
RefreshTokenExpiresAt: time.Now().UTC().Unix() + int64(defaultRefreshTokenExpiresIn.Seconds()),
RefreshTokenExpiresIn: int64(defaultRefreshTokenExpiresIn.Seconds()),
Scopes: strings.Split(tokenResponse.Data.Scope, " "),
TokenType: tokenResponse.Data.TokenType,
}
}