@@ -121,7 +121,7 @@ var (
121
121
ApprovalForce AuthCodeOption = SetAuthURLParam ("prompt" , "consent" )
122
122
)
123
123
124
- // An AuthCodeOption is passed to Config.AuthCodeURL.
124
+ // An AuthCodeOption may be passed to Config.AuthCodeURL or Config.Exchange .
125
125
type AuthCodeOption interface {
126
126
setValue (url.Values )
127
127
}
@@ -139,16 +139,12 @@ func SetAuthURLParam(key, value string) AuthCodeOption {
139
139
// AuthCodeURL returns a URL to OAuth 2.0 provider's consent page
140
140
// that asks for permissions for the required scopes explicitly.
141
141
//
142
- // State is a token to protect the user from CSRF attacks. You must
143
- // always provide a non-empty string and validate that it matches the
144
- // state query parameter on your redirect callback.
145
- // See http://tools.ietf.org/html/rfc6749#section-10.12 for more info.
142
+ // State is an opaque value used by the client to maintain state
143
+ // between the request and callback.
146
144
//
147
145
// Opts may include AccessTypeOnline or AccessTypeOffline, as well
148
146
// as ApprovalForce.
149
- // It can also be used to pass the PKCE challenge.
150
- // See https://www.oauth.com/oauth2-servers/pkce/ for more info.
151
- func (c * Config ) AuthCodeURL (state string , opts ... AuthCodeOption ) string {
147
+ func (c * Config ) AuthCodeURLWithPKCE (state string , pkce * PKCEParams , opts ... AuthCodeOption ) string {
152
148
var buf bytes.Buffer
153
149
buf .WriteString (c .Endpoint .AuthURL )
154
150
v := url.Values {
@@ -162,9 +158,11 @@ func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string {
162
158
v .Set ("scope" , strings .Join (c .Scopes , " " ))
163
159
}
164
160
if state != "" {
165
- // TODO(light): Docs say never to omit state; don't allow empty.
166
161
v .Set ("state" , state )
167
162
}
163
+ if pkce != nil {
164
+ pkce .challengeOption ().setValue (v )
165
+ }
168
166
for _ , opt := range opts {
169
167
opt .setValue (v )
170
168
}
@@ -177,6 +175,10 @@ func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string {
177
175
return buf .String ()
178
176
}
179
177
178
+ func (c * Config ) AuthCodeURL (state string , opts ... AuthCodeOption ) string {
179
+ return c .AuthCodeURLWithPKCE (state , nil , opts ... )
180
+ }
181
+
180
182
// PasswordCredentialsToken converts a resource owner username and password
181
183
// pair into a token.
182
184
//
@@ -208,24 +210,28 @@ func (c *Config) PasswordCredentialsToken(ctx context.Context, username, passwor
208
210
//
209
211
// The code will be in the *http.Request.FormValue("code"). Before
210
212
// calling Exchange, be sure to validate FormValue("state").
211
- //
212
- // Opts may include the PKCE verifier code if previously used in AuthCodeURL.
213
- // See https://www.oauth.com/oauth2-servers/pkce/ for more info.
214
- func (c * Config ) Exchange (ctx context.Context , code string , opts ... AuthCodeOption ) (* Token , error ) {
213
+ func (c * Config ) ExchangeWithPKCE (ctx context.Context , code string , pkce * PKCEParams , opts ... AuthCodeOption ) (* Token , error ) {
215
214
v := url.Values {
216
215
"grant_type" : {"authorization_code" },
217
216
"code" : {code },
218
217
}
219
218
if c .RedirectURL != "" {
220
219
v .Set ("redirect_uri" , c .RedirectURL )
221
220
}
221
+ if pkce != nil {
222
+ pkce .verifierOption ().setValue (v )
223
+ }
222
224
for _ , opt := range opts {
223
225
opt .setValue (v )
224
226
}
225
227
return retrieveToken (ctx , c , v )
226
228
}
227
229
228
- // Client returns an HTTP client using the provided token.
230
+ func (c * Config ) Exchange (ctx context.Context , code string , opts ... AuthCodeOption ) (* Token , error ) {
231
+ return c .ExchangeWithPKCE (ctx , code , nil , opts ... )
232
+ }
233
+
234
+ `345432Q// Client returns an HTTP client using the provided token.
229
235
// The token will auto-refresh as necessary. The underlying
230
236
// HTTP transport will be obtained using the provided context.
231
237
// The returned client and its Transport should not be modified.
0 commit comments