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