...
1
2
3
4
5 package oauth2
6
7 import (
8 "context"
9 "fmt"
10 "net/http"
11 "net/url"
12 "strconv"
13 "strings"
14 "time"
15
16 "golang.org/x/oauth2/internal"
17 )
18
19
20
21
22 const defaultExpiryDelta = 10 * time.Second
23
24
25
26
27
28
29
30
31 type Token struct {
32
33
34 AccessToken string `json:"access_token"`
35
36
37
38 TokenType string `json:"token_type,omitempty"`
39
40
41
42
43 RefreshToken string `json:"refresh_token,omitempty"`
44
45
46
47
48
49
50 Expiry time.Time `json:"expiry,omitempty"`
51
52
53
54 raw interface{}
55
56
57
58
59 expiryDelta time.Duration
60 }
61
62
63 func (t *Token) Type() string {
64 if strings.EqualFold(t.TokenType, "bearer") {
65 return "Bearer"
66 }
67 if strings.EqualFold(t.TokenType, "mac") {
68 return "MAC"
69 }
70 if strings.EqualFold(t.TokenType, "basic") {
71 return "Basic"
72 }
73 if t.TokenType != "" {
74 return t.TokenType
75 }
76 return "Bearer"
77 }
78
79
80
81
82
83
84 func (t *Token) SetAuthHeader(r *http.Request) {
85 r.Header.Set("Authorization", t.Type()+" "+t.AccessToken)
86 }
87
88
89
90
91 func (t *Token) WithExtra(extra interface{}) *Token {
92 t2 := new(Token)
93 *t2 = *t
94 t2.raw = extra
95 return t2
96 }
97
98
99
100
101 func (t *Token) Extra(key string) interface{} {
102 if raw, ok := t.raw.(map[string]interface{}); ok {
103 return raw[key]
104 }
105
106 vals, ok := t.raw.(url.Values)
107 if !ok {
108 return nil
109 }
110
111 v := vals.Get(key)
112 switch s := strings.TrimSpace(v); strings.Count(s, ".") {
113 case 0:
114 if i, err := strconv.ParseInt(s, 10, 64); err == nil {
115 return i
116 }
117 case 1:
118 if f, err := strconv.ParseFloat(s, 64); err == nil {
119 return f
120 }
121 }
122
123 return v
124 }
125
126
127 var timeNow = time.Now
128
129
130
131 func (t *Token) expired() bool {
132 if t.Expiry.IsZero() {
133 return false
134 }
135
136 expiryDelta := defaultExpiryDelta
137 if t.expiryDelta != 0 {
138 expiryDelta = t.expiryDelta
139 }
140 return t.Expiry.Round(0).Add(-expiryDelta).Before(timeNow())
141 }
142
143
144 func (t *Token) Valid() bool {
145 return t != nil && t.AccessToken != "" && !t.expired()
146 }
147
148
149
150 func tokenFromInternal(t *internal.Token) *Token {
151 if t == nil {
152 return nil
153 }
154 return &Token{
155 AccessToken: t.AccessToken,
156 TokenType: t.TokenType,
157 RefreshToken: t.RefreshToken,
158 Expiry: t.Expiry,
159 raw: t.Raw,
160 }
161 }
162
163
164
165
166 func retrieveToken(ctx context.Context, c *Config, v url.Values) (*Token, error) {
167 tk, err := internal.RetrieveToken(ctx, c.ClientID, c.ClientSecret, c.Endpoint.TokenURL, v, internal.AuthStyle(c.Endpoint.AuthStyle), c.authStyleCache.Get())
168 if err != nil {
169 if rErr, ok := err.(*internal.RetrieveError); ok {
170 return nil, (*RetrieveError)(rErr)
171 }
172 return nil, err
173 }
174 return tokenFromInternal(tk), nil
175 }
176
177
178
179
180 type RetrieveError struct {
181 Response *http.Response
182
183
184 Body []byte
185
186 ErrorCode string
187
188 ErrorDescription string
189
190 ErrorURI string
191 }
192
193 func (r *RetrieveError) Error() string {
194 if r.ErrorCode != "" {
195 s := fmt.Sprintf("oauth2: %q", r.ErrorCode)
196 if r.ErrorDescription != "" {
197 s += fmt.Sprintf(" %q", r.ErrorDescription)
198 }
199 if r.ErrorURI != "" {
200 s += fmt.Sprintf(" %q", r.ErrorURI)
201 }
202 return s
203 }
204 return fmt.Sprintf("oauth2: cannot fetch token: %v\nResponse: %s", r.Response.Status, r.Body)
205 }
206
View as plain text