vendor: golang.org/x/oauth2 v0.35.0

full diff: https://cs.opensource.google/go/x/oauth2/+/refs/tags/v0.28.0...refs/tags/v0.35.0

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn
2026-02-12 17:21:05 +01:00
committed by Milos Gajdos
parent ae7c498d28
commit 9b79cf5105
24 changed files with 303 additions and 170 deletions

2
go.mod
View File

@@ -37,7 +37,7 @@ require (
go.opentelemetry.io/otel/trace v1.32.0
golang.org/x/crypto v0.48.0
golang.org/x/net v0.50.0
golang.org/x/oauth2 v0.28.0
golang.org/x/oauth2 v0.35.0
golang.org/x/sync v0.19.0
google.golang.org/api v0.197.0
gopkg.in/yaml.v2 v2.4.0

4
go.sum
View File

@@ -334,8 +334,8 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=
golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=

View File

@@ -34,7 +34,7 @@ type PKCEParams struct {
// and returns an auth code and state upon approval.
type AuthorizationHandler func(authCodeURL string) (code string, state string, err error)
// TokenSourceWithPKCE is an enhanced version of TokenSource with PKCE support.
// TokenSourceWithPKCE is an enhanced version of [oauth2.TokenSource] with PKCE support.
//
// The pkce parameter supports PKCE flow, which uses code challenge and code verifier
// to prevent CSRF attacks. A unique code challenge and code verifier should be generated
@@ -43,12 +43,12 @@ func TokenSourceWithPKCE(ctx context.Context, config *oauth2.Config, state strin
return oauth2.ReuseTokenSource(nil, authHandlerSource{config: config, ctx: ctx, authHandler: authHandler, state: state, pkce: pkce})
}
// TokenSource returns an oauth2.TokenSource that fetches access tokens
// TokenSource returns an [oauth2.TokenSource] that fetches access tokens
// using 3-legged-OAuth flow.
//
// The provided context.Context is used for oauth2 Exchange operation.
// The provided [context.Context] is used for oauth2 Exchange operation.
//
// The provided oauth2.Config should be a full configuration containing AuthURL,
// The provided [oauth2.Config] should be a full configuration containing AuthURL,
// TokenURL, and Scope.
//
// An environment-specific AuthorizationHandler is used to obtain user consent.

View File

@@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"io"
"mime"
"net/http"
"net/url"
"strings"
@@ -116,10 +117,38 @@ func retrieveDeviceAuth(ctx context.Context, c *Config, v url.Values) (*DeviceAu
return nil, fmt.Errorf("oauth2: cannot auth device: %v", err)
}
if code := r.StatusCode; code < 200 || code > 299 {
return nil, &RetrieveError{
retrieveError := &RetrieveError{
Response: r,
Body: body,
}
content, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
switch content {
case "application/x-www-form-urlencoded", "text/plain":
// some endpoints return a query string
vals, err := url.ParseQuery(string(body))
if err != nil {
return nil, retrieveError
}
retrieveError.ErrorCode = vals.Get("error")
retrieveError.ErrorDescription = vals.Get("error_description")
retrieveError.ErrorURI = vals.Get("error_uri")
default:
var tj struct {
// https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
ErrorCode string `json:"error"`
ErrorDescription string `json:"error_description"`
ErrorURI string `json:"error_uri"`
}
if json.Unmarshal(body, &tj) != nil {
return nil, retrieveError
}
retrieveError.ErrorCode = tj.ErrorCode
retrieveError.ErrorDescription = tj.ErrorDescription
retrieveError.ErrorURI = tj.ErrorURI
}
return nil, retrieveError
}
da := &DeviceAuthResponse{}

View File

@@ -153,6 +153,43 @@ func (params CredentialsParams) deepCopy() CredentialsParams {
return paramsCopy
}
// CredentialsType specifies the type of JSON credentials being provided
// to a loading function.
type CredentialsType string
const (
// ServiceAccount represents a service account file type.
ServiceAccount CredentialsType = "service_account"
// AuthorizedUser represents a user credentials file type.
AuthorizedUser CredentialsType = "authorized_user"
// ExternalAccount represents an external account file type.
//
// IMPORTANT:
// This credential type does not validate the credential configuration. A security
// risk occurs when a credential configuration configured with malicious urls
// is used.
// You should validate credential configurations provided by untrusted sources.
// See [Security requirements when using credential configurations from an external
// source] https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
// for more details.
ExternalAccount CredentialsType = "external_account"
// ExternalAccountAuthorizedUser represents an external account authorized user file type.
ExternalAccountAuthorizedUser CredentialsType = "external_account_authorized_user"
// ImpersonatedServiceAccount represents an impersonated service account file type.
//
// IMPORTANT:
// This credential type does not validate the credential configuration. A security
// risk occurs when a credential configuration configured with malicious urls
// is used.
// You should validate credential configurations provided by untrusted sources.
// See [Security requirements when using credential configurations from an external
// source] https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
// for more details.
ImpersonatedServiceAccount CredentialsType = "impersonated_service_account"
// GDCHServiceAccount represents a GDCH service account credentials.
GDCHServiceAccount CredentialsType = "gdch_service_account"
)
// DefaultClient returns an HTTP Client that uses the
// DefaultTokenSource to obtain authentication credentials.
func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) {
@@ -246,17 +283,71 @@ func FindDefaultCredentials(ctx context.Context, scopes ...string) (*Credentials
return FindDefaultCredentialsWithParams(ctx, params)
}
// CredentialsFromJSONWithParams obtains Google credentials from a JSON value. The JSON can
// represent either a Google Developers Console client_credentials.json file (as in ConfigFromJSON),
// a Google Developers service account key file, a gcloud user credentials file (a.k.a. refresh
// token JSON), or the JSON configuration file for workload identity federation in non-Google cloud
// platforms (see https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation).
// CredentialsFromJSONWithType invokes CredentialsFromJSONWithTypeAndParams with the specified scopes.
//
// Important: If you accept a credential configuration (credential JSON/File/Stream) from an
// external source for authentication to Google Cloud Platform, you must validate it before
// providing it to any Google API or library. Providing an unvalidated credential configuration to
// Google APIs can compromise the security of your systems and data. For more information, refer to
// [Validate credential configurations from external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
func CredentialsFromJSONWithType(ctx context.Context, jsonData []byte, credType CredentialsType, scopes ...string) (*Credentials, error) {
var params CredentialsParams
params.Scopes = scopes
return CredentialsFromJSONWithTypeAndParams(ctx, jsonData, credType, params)
}
// CredentialsFromJSONWithTypeAndParams obtains Google credentials from a JSON value and
// validates that the credentials match the specified type.
//
// Important: If you accept a credential configuration (credential JSON/File/Stream) from an
// external source for authentication to Google Cloud Platform, you must validate it before
// providing it to any Google API or library. Providing an unvalidated credential configuration to
// Google APIs can compromise the security of your systems and data. For more information, refer to
// [Validate credential configurations from external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
func CredentialsFromJSONWithTypeAndParams(ctx context.Context, jsonData []byte, credType CredentialsType, params CredentialsParams) (*Credentials, error) {
var f struct {
Type string `json:"type"`
}
if err := json.Unmarshal(jsonData, &f); err != nil {
return nil, err
}
if CredentialsType(f.Type) != credType {
return nil, fmt.Errorf("google: expected credential type %q, found %q", credType, f.Type)
}
return CredentialsFromJSONWithParams(ctx, jsonData, params)
}
// CredentialsFromJSONWithParams obtains Google credentials from a JSON value. The JSON can
// represent either a Google Developers Console client_credentials.json file (as in ConfigFromJSON),
// a Google Developers service account key file, a gcloud user credentials file (a.k.a. refresh
// token JSON), or the JSON configuration file for workload identity federation in non-Google cloud
// platforms (see https://cloud.google.com/iam/docs/how-to#using-workload-identity-federation).
//
// Deprecated: This function is deprecated because of a potential security risk.
// It does not validate the credential configuration. The security risk occurs
// when a credential configuration is accepted from a source that is not
// under your control and used without validation on your side.
//
// If you know that you will be loading credential configurations of a
// specific type, it is recommended to use a credential-type-specific
// CredentialsFromJSONWithTypeAndParams method. This will ensure that an unexpected
// credential type with potential for malicious intent is not loaded
// unintentionally. You might still have to do validation for certain
// credential types. Please follow the recommendation for that method. For
// example, if you want to load only service accounts, you can use
//
// creds, err := google.CredentialsFromJSONWithTypeAndParams(ctx, jsonData, google.ServiceAccount, params)
//
// If you are loading your credential configuration from an untrusted source
// and have not mitigated the risks (e.g. by validating the configuration
// yourself), make these changes as soon as possible to prevent security
// risks to your environment.
//
// Regardless of the method used, it is always your responsibility to
// validate configurations received from external sources.
//
// For more details see:
// https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
func CredentialsFromJSONWithParams(ctx context.Context, jsonData []byte, params CredentialsParams) (*Credentials, error) {
// Make defensive copy of the slices in params.
params = params.deepCopy()
@@ -301,11 +392,31 @@ func CredentialsFromJSONWithParams(ctx context.Context, jsonData []byte, params
// CredentialsFromJSON invokes CredentialsFromJSONWithParams with the specified scopes.
//
// Important: If you accept a credential configuration (credential JSON/File/Stream) from an
// external source for authentication to Google Cloud Platform, you must validate it before
// providing it to any Google API or library. Providing an unvalidated credential configuration to
// Google APIs can compromise the security of your systems and data. For more information, refer to
// [Validate credential configurations from external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).
// Deprecated: This function is deprecated because of a potential security risk.
// It does not validate the credential configuration. The security risk occurs
// when a credential configuration is accepted from a source that is not
// under your control and used without validation on your side.
//
// If you know that you will be loading credential configurations of a
// specific type, it is recommended to use a credential-type-specific
// CredentialsFromJSONWithType method. This will ensure that an unexpected
// credential type with potential for malicious intent is not loaded
// unintentionally. You might still have to do validation for certain
// credential types. Please follow the recommendation for that method. For
// example, if you want to load only service accounts, you can use
//
// creds, err := google.CredentialsFromJSONWithType(ctx, jsonData, google.ServiceAccount, scopes...)
//
// If you are loading your credential configuration from an untrusted source
// and have not mitigated the risks (e.g. by validating the configuration
// yourself), make these changes as soon as possible to prevent security
// risks to your environment.
//
// Regardless of the method used, it is always your responsibility to
// validate configurations received from external sources.
//
// For more details see:
// https://cloud.google.com/docs/authentication/external/externally-sourced-credentials
func CredentialsFromJSON(ctx context.Context, jsonData []byte, scopes ...string) (*Credentials, error) {
var params CredentialsParams
params.Scopes = scopes

View File

@@ -5,7 +5,6 @@
package externalaccount
import (
"bytes"
"context"
"crypto/hmac"
"crypto/sha256"
@@ -14,7 +13,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
@@ -149,13 +147,13 @@ func canonicalHeaders(req *http.Request) (string, string) {
}
sort.Strings(headers)
var fullHeaders bytes.Buffer
var fullHeaders strings.Builder
for _, header := range headers {
headerValue := strings.Join(lowerCaseHeaders[header], ",")
fullHeaders.WriteString(header)
fullHeaders.WriteRune(':')
fullHeaders.WriteByte(':')
fullHeaders.WriteString(headerValue)
fullHeaders.WriteRune('\n')
fullHeaders.WriteByte('\n')
}
return strings.Join(headers, ";"), fullHeaders.String()
@@ -170,7 +168,7 @@ func requestDataHash(req *http.Request) (string, error) {
}
defer requestBody.Close()
requestData, err = ioutil.ReadAll(io.LimitReader(requestBody, 1<<20))
requestData, err = io.ReadAll(io.LimitReader(requestBody, 1<<20))
if err != nil {
return "", err
}
@@ -419,7 +417,7 @@ func (cs *awsCredentialSource) getAWSSessionToken() (string, error) {
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
respBody, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
if err != nil {
return "", err
}
@@ -462,7 +460,7 @@ func (cs *awsCredentialSource) getRegion(headers map[string]string) (string, err
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
respBody, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
if err != nil {
return "", err
}
@@ -531,7 +529,7 @@ func (cs *awsCredentialSource) getMetadataSecurityCredentials(roleName string, h
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
respBody, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
if err != nil {
return result, err
}
@@ -564,7 +562,7 @@ func (cs *awsCredentialSource) getMetadataRoleName(headers map[string]string) (s
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
respBody, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
if err != nil {
return "", err
}

View File

@@ -486,11 +486,11 @@ func (ts tokenSource) Token() (*oauth2.Token, error) {
ClientID: conf.ClientID,
ClientSecret: conf.ClientSecret,
}
var options map[string]interface{}
var options map[string]any
// Do not pass workforce_pool_user_project when client authentication is used.
// The client ID is sufficient for determining the user project.
if conf.WorkforcePoolUserProject != "" && conf.ClientID == "" {
options = map[string]interface{}{
options = map[string]any{
"userProject": conf.WorkforcePoolUserProject,
}
}

View File

@@ -11,7 +11,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"regexp"
@@ -258,7 +257,7 @@ func (cs executableCredentialSource) getTokenFromOutputFile() (token string, err
}
defer file.Close()
data, err := ioutil.ReadAll(io.LimitReader(file, 1<<20))
data, err := io.ReadAll(io.LimitReader(file, 1<<20))
if err != nil || len(data) == 0 {
// Cachefile exists, but no data found. Get new credential.
return "", nil

View File

@@ -10,7 +10,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
)
@@ -29,14 +28,14 @@ func (cs fileCredentialSource) subjectToken() (string, error) {
return "", fmt.Errorf("oauth2/google/externalaccount: failed to open credential file %q", cs.File)
}
defer tokenFile.Close()
tokenBytes, err := ioutil.ReadAll(io.LimitReader(tokenFile, 1<<20))
tokenBytes, err := io.ReadAll(io.LimitReader(tokenFile, 1<<20))
if err != nil {
return "", fmt.Errorf("oauth2/google/externalaccount: failed to read credential file: %v", err)
}
tokenBytes = bytes.TrimSpace(tokenBytes)
switch cs.Format.Type {
case "json":
jsonData := make(map[string]interface{})
jsonData := make(map[string]any)
err = json.Unmarshal(tokenBytes, &jsonData)
if err != nil {
return "", fmt.Errorf("oauth2/google/externalaccount: failed to unmarshal subject token file: %v", err)

View File

@@ -10,7 +10,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"golang.org/x/oauth2"
@@ -44,7 +43,7 @@ func (cs urlCredentialSource) subjectToken() (string, error) {
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
respBody, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
if err != nil {
return "", fmt.Errorf("oauth2/google/externalaccount: invalid body in subject token URL query: %v", err)
}
@@ -54,7 +53,7 @@ func (cs urlCredentialSource) subjectToken() (string, error) {
switch cs.Format.Type {
case "json":
jsonData := make(map[string]interface{})
jsonData := make(map[string]any)
err = json.Unmarshal(respBody, &jsonData)
if err != nil {
return "", fmt.Errorf("oauth2/google/externalaccount: failed to unmarshal subject token file: %v", err)

View File

@@ -103,6 +103,7 @@ const (
externalAccountKey = "external_account"
externalAccountAuthorizedUserKey = "external_account_authorized_user"
impersonatedServiceAccount = "impersonated_service_account"
gdchServiceAccountKey = "gdch_service_account"
)
// credentialsFile is the unmarshalled representation of a credentials file.
@@ -165,7 +166,7 @@ func (f *credentialsFile) jwtConfig(scopes []string, subject string) *jwt.Config
func (f *credentialsFile) tokenSource(ctx context.Context, params CredentialsParams) (oauth2.TokenSource, error) {
switch f.Type {
case serviceAccountKey:
case serviceAccountKey, gdchServiceAccountKey:
cfg := f.jwtConfig(params.Scopes, params.Subject)
return cfg.TokenSource(ctx), nil
case userCredentialsKey:
@@ -252,7 +253,7 @@ func (f *credentialsFile) tokenSource(ctx context.Context, params CredentialsPar
// Further information about retrieving access tokens from the GCE metadata
// server can be found at https://cloud.google.com/compute/docs/authentication.
func ComputeTokenSource(account string, scope ...string) oauth2.TokenSource {
// refresh 3 minutes and 45 seconds early. The shortest MDS cache is currently 4 minutes, so any
// Refresh 3 minutes and 45 seconds early. The shortest MDS cache is currently 4 minutes, so any
// refreshes earlier are a waste of compute.
earlyExpirySecs := 225 * time.Second
return computeTokenSource(account, earlyExpirySecs, scope...)
@@ -285,27 +286,23 @@ func (cs computeSource) Token() (*oauth2.Token, error) {
if err != nil {
return nil, err
}
var res struct {
AccessToken string `json:"access_token"`
ExpiresInSec int `json:"expires_in"`
TokenType string `json:"token_type"`
}
var res oauth2.Token
err = json.NewDecoder(strings.NewReader(tokenJSON)).Decode(&res)
if err != nil {
return nil, fmt.Errorf("oauth2/google: invalid token JSON from metadata: %v", err)
}
if res.ExpiresInSec == 0 || res.AccessToken == "" {
if res.ExpiresIn == 0 || res.AccessToken == "" {
return nil, fmt.Errorf("oauth2/google: incomplete token received from metadata")
}
tok := &oauth2.Token{
AccessToken: res.AccessToken,
TokenType: res.TokenType,
Expiry: time.Now().Add(time.Duration(res.ExpiresInSec) * time.Second),
Expiry: time.Now().Add(time.Duration(res.ExpiresIn) * time.Second),
}
// NOTE(cbro): add hidden metadata about where the token is from.
// This is needed for detection by client libraries to know that credentials come from the metadata server.
// This may be removed in a future version of this library.
return tok.WithExtra(map[string]interface{}{
return tok.WithExtra(map[string]any{
"oauth2.google.tokenSource": "compute-metadata",
"oauth2.google.serviceAccount": acct,
}), nil

View File

@@ -10,7 +10,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"time"
@@ -81,7 +80,7 @@ func (its ImpersonateTokenSource) Token() (*oauth2.Token, error) {
return nil, fmt.Errorf("oauth2/google: unable to generate access token: %v", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
if err != nil {
return nil, fmt.Errorf("oauth2/google: unable to read body: %v", err)
}

View File

@@ -9,7 +9,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strconv"
@@ -28,7 +27,7 @@ func defaultHeader() http.Header {
// The first 4 fields are all mandatory. headers can be used to pass additional
// headers beyond the bare minimum required by the token exchange. options can
// be used to pass additional JSON-structured options to the remote server.
func ExchangeToken(ctx context.Context, endpoint string, request *TokenExchangeRequest, authentication ClientAuthentication, headers http.Header, options map[string]interface{}) (*Response, error) {
func ExchangeToken(ctx context.Context, endpoint string, request *TokenExchangeRequest, authentication ClientAuthentication, headers http.Header, options map[string]any) (*Response, error) {
data := url.Values{}
data.Set("audience", request.Audience)
data.Set("grant_type", "urn:ietf:params:oauth:grant-type:token-exchange")
@@ -82,7 +81,7 @@ func makeRequest(ctx context.Context, endpoint string, data url.Values, authenti
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
if err != nil {
return nil, err
}

View File

@@ -2,5 +2,5 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package internal contains support packages for oauth2 package.
// Package internal contains support packages for [golang.org/x/oauth2].
package internal

View File

@@ -13,7 +13,7 @@ import (
)
// ParseKey converts the binary contents of a private key file
// to an *rsa.PrivateKey. It detects whether the private key is in a
// to an [*rsa.PrivateKey]. It detects whether the private key is in a
// PEM container or not. If so, it extracts the private key
// from PEM container before conversion. It only supports PEM
// containers with no passphrase.

View File

@@ -10,7 +10,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"math"
"mime"
"net/http"
@@ -26,9 +25,9 @@ import (
// the requests to access protected resources on the OAuth 2.0
// provider's backend.
//
// This type is a mirror of oauth2.Token and exists to break
// This type is a mirror of [golang.org/x/oauth2.Token] and exists to break
// an otherwise-circular dependency. Other internal packages
// should convert this Token into an oauth2.Token before use.
// should convert this Token into an [golang.org/x/oauth2.Token] before use.
type Token struct {
// AccessToken is the token that authorizes and authenticates
// the requests.
@@ -50,9 +49,16 @@ type Token struct {
// mechanisms for that TokenSource will not be used.
Expiry time.Time
// ExpiresIn is the OAuth2 wire format "expires_in" field,
// which specifies how many seconds later the token expires,
// relative to an unknown time base approximately around "now".
// It is the application's responsibility to populate
// `Expiry` from `ExpiresIn` when required.
ExpiresIn int64 `json:"expires_in,omitempty"`
// Raw optionally contains extra metadata from the server
// when updating a token.
Raw interface{}
Raw any
}
// tokenJSON is the struct representing the HTTP response from OAuth2
@@ -99,14 +105,6 @@ func (e *expirationTime) UnmarshalJSON(b []byte) error {
return nil
}
// RegisterBrokenAuthHeaderProvider previously did something. It is now a no-op.
//
// Deprecated: this function no longer does anything. Caller code that
// wants to avoid potential extra HTTP requests made during
// auto-probing of the provider's auth style should set
// Endpoint.AuthStyle.
func RegisterBrokenAuthHeaderProvider(tokenURL string) {}
// AuthStyle is a copy of the golang.org/x/oauth2 package's AuthStyle type.
type AuthStyle int
@@ -143,6 +141,11 @@ func (lc *LazyAuthStyleCache) Get() *AuthStyleCache {
return c
}
type authStyleCacheKey struct {
url string
clientID string
}
// AuthStyleCache is the set of tokenURLs we've successfully used via
// RetrieveToken and which style auth we ended up using.
// It's called a cache, but it doesn't (yet?) shrink. It's expected that
@@ -150,26 +153,26 @@ func (lc *LazyAuthStyleCache) Get() *AuthStyleCache {
// small.
type AuthStyleCache struct {
mu sync.Mutex
m map[string]AuthStyle // keyed by tokenURL
m map[authStyleCacheKey]AuthStyle
}
// lookupAuthStyle reports which auth style we last used with tokenURL
// when calling RetrieveToken and whether we have ever done so.
func (c *AuthStyleCache) lookupAuthStyle(tokenURL string) (style AuthStyle, ok bool) {
func (c *AuthStyleCache) lookupAuthStyle(tokenURL, clientID string) (style AuthStyle, ok bool) {
c.mu.Lock()
defer c.mu.Unlock()
style, ok = c.m[tokenURL]
style, ok = c.m[authStyleCacheKey{tokenURL, clientID}]
return
}
// setAuthStyle adds an entry to authStyleCache, documented above.
func (c *AuthStyleCache) setAuthStyle(tokenURL string, v AuthStyle) {
func (c *AuthStyleCache) setAuthStyle(tokenURL, clientID string, v AuthStyle) {
c.mu.Lock()
defer c.mu.Unlock()
if c.m == nil {
c.m = make(map[string]AuthStyle)
c.m = make(map[authStyleCacheKey]AuthStyle)
}
c.m[tokenURL] = v
c.m[authStyleCacheKey{tokenURL, clientID}] = v
}
// newTokenRequest returns a new *http.Request to retrieve a new token
@@ -210,9 +213,9 @@ func cloneURLValues(v url.Values) url.Values {
}
func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values, authStyle AuthStyle, styleCache *AuthStyleCache) (*Token, error) {
needsAuthStyleProbe := authStyle == 0
needsAuthStyleProbe := authStyle == AuthStyleUnknown
if needsAuthStyleProbe {
if style, ok := styleCache.lookupAuthStyle(tokenURL); ok {
if style, ok := styleCache.lookupAuthStyle(tokenURL, clientID); ok {
authStyle = style
needsAuthStyleProbe = false
} else {
@@ -242,7 +245,7 @@ func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string,
token, err = doTokenRoundTrip(ctx, req)
}
if needsAuthStyleProbe && err == nil {
styleCache.setAuthStyle(tokenURL, authStyle)
styleCache.setAuthStyle(tokenURL, clientID, authStyle)
}
// Don't overwrite `RefreshToken` with an empty value
// if this was a token refreshing request.
@@ -257,7 +260,7 @@ func doTokenRoundTrip(ctx context.Context, req *http.Request) (*Token, error) {
if err != nil {
return nil, err
}
body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1<<20))
body, err := io.ReadAll(io.LimitReader(r.Body, 1<<20))
r.Body.Close()
if err != nil {
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
@@ -312,7 +315,8 @@ func doTokenRoundTrip(ctx context.Context, req *http.Request) (*Token, error) {
TokenType: tj.TokenType,
RefreshToken: tj.RefreshToken,
Expiry: tj.expiry(),
Raw: make(map[string]interface{}),
ExpiresIn: int64(tj.ExpiresIn),
Raw: make(map[string]any),
}
json.Unmarshal(body, &token.Raw) // no error checks for optional fields
}

View File

@@ -9,8 +9,8 @@ import (
"net/http"
)
// HTTPClient is the context key to use with golang.org/x/net/context's
// WithValue function to associate an *http.Client value with a context.
// HTTPClient is the context key to use with [context.WithValue]
// to associate an [*http.Client] value with a context.
var HTTPClient ContextKey
// ContextKey is just an empty struct. It exists so HTTPClient can be

View File

@@ -4,7 +4,7 @@
// Package jws provides a partial implementation
// of JSON Web Signature encoding and decoding.
// It exists to support the golang.org/x/oauth2 package.
// It exists to support the [golang.org/x/oauth2] package.
//
// See RFC 7515.
//
@@ -48,7 +48,7 @@ type ClaimSet struct {
// See http://tools.ietf.org/html/draft-jones-json-web-token-10#section-4.3
// This array is marshalled using custom code (see (c *ClaimSet) encode()).
PrivateClaims map[string]interface{} `json:"-"`
PrivateClaims map[string]any `json:"-"`
}
func (c *ClaimSet) encode() (string, error) {
@@ -116,12 +116,12 @@ func (h *Header) encode() (string, error) {
// Decode decodes a claim set from a JWS payload.
func Decode(payload string) (*ClaimSet, error) {
// decode returned id token to get expiry
s := strings.Split(payload, ".")
if len(s) < 2 {
_, claims, _, ok := parseToken(payload)
if !ok {
// TODO(jbd): Provide more context about the error.
return nil, errors.New("jws: invalid token received")
}
decoded, err := base64.RawURLEncoding.DecodeString(s[1])
decoded, err := base64.RawURLEncoding.DecodeString(claims)
if err != nil {
return nil, err
}
@@ -152,7 +152,7 @@ func EncodeWithSigner(header *Header, c *ClaimSet, sg Signer) (string, error) {
}
// Encode encodes a signed JWS with provided header and claim set.
// This invokes EncodeWithSigner using crypto/rsa.SignPKCS1v15 with the given RSA private key.
// This invokes [EncodeWithSigner] using [crypto/rsa.SignPKCS1v15] with the given RSA private key.
func Encode(header *Header, c *ClaimSet, key *rsa.PrivateKey) (string, error) {
sg := func(data []byte) (sig []byte, err error) {
h := sha256.New()
@@ -165,18 +165,34 @@ func Encode(header *Header, c *ClaimSet, key *rsa.PrivateKey) (string, error) {
// Verify tests whether the provided JWT token's signature was produced by the private key
// associated with the supplied public key.
func Verify(token string, key *rsa.PublicKey) error {
if strings.Count(token, ".") != 2 {
header, claims, sig, ok := parseToken(token)
if !ok {
return errors.New("jws: invalid token received, token must have 3 parts")
}
parts := strings.SplitN(token, ".", 3)
signedContent := parts[0] + "." + parts[1]
signatureString, err := base64.RawURLEncoding.DecodeString(parts[2])
signatureString, err := base64.RawURLEncoding.DecodeString(sig)
if err != nil {
return err
}
h := sha256.New()
h.Write([]byte(signedContent))
h.Write([]byte(header + tokenDelim + claims))
return rsa.VerifyPKCS1v15(key, crypto.SHA256, h.Sum(nil), signatureString)
}
func parseToken(s string) (header, claims, sig string, ok bool) {
header, s, ok = strings.Cut(s, tokenDelim)
if !ok { // no period found
return "", "", "", false
}
claims, s, ok = strings.Cut(s, tokenDelim)
if !ok { // only one period found
return "", "", "", false
}
sig, _, ok = strings.Cut(s, tokenDelim)
if ok { // three periods found
return "", "", "", false
}
return header, claims, sig, true
}
const tokenDelim = "."

View File

@@ -13,7 +13,6 @@ import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strings"
@@ -69,7 +68,7 @@ type Config struct {
// PrivateClaims optionally specifies custom private claims in the JWT.
// See http://tools.ietf.org/html/draft-jones-json-web-token-10#section-4.3
PrivateClaims map[string]interface{}
PrivateClaims map[string]any
// UseIDToken optionally specifies whether ID token should be used instead
// of access token when the server returns both.
@@ -136,7 +135,7 @@ func (js jwtSource) Token() (*oauth2.Token, error) {
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 1<<20))
body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
if err != nil {
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
}
@@ -148,10 +147,8 @@ func (js jwtSource) Token() (*oauth2.Token, error) {
}
// tokenRes is the JSON response body.
var tokenRes struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
IDToken string `json:"id_token"`
ExpiresIn int64 `json:"expires_in"` // relative seconds from now
oauth2.Token
IDToken string `json:"id_token"`
}
if err := json.Unmarshal(body, &tokenRes); err != nil {
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
@@ -160,7 +157,7 @@ func (js jwtSource) Token() (*oauth2.Token, error) {
AccessToken: tokenRes.AccessToken,
TokenType: tokenRes.TokenType,
}
raw := make(map[string]interface{})
raw := make(map[string]any)
json.Unmarshal(body, &raw) // no error checks for optional fields
token = token.WithExtra(raw)

60
vendor/golang.org/x/oauth2/oauth2.go generated vendored
View File

@@ -9,7 +9,6 @@
package oauth2 // import "golang.org/x/oauth2"
import (
"bytes"
"context"
"errors"
"net/http"
@@ -22,9 +21,9 @@ import (
)
// NoContext is the default context you should supply if not using
// your own context.Context (see https://golang.org/x/net/context).
// your own [context.Context].
//
// Deprecated: Use context.Background() or context.TODO() instead.
// Deprecated: Use [context.Background] or [context.TODO] instead.
var NoContext = context.TODO()
// RegisterBrokenAuthHeaderProvider previously did something. It is now a no-op.
@@ -37,8 +36,8 @@ func RegisterBrokenAuthHeaderProvider(tokenURL string) {}
// Config describes a typical 3-legged OAuth2 flow, with both the
// client application information and the server's endpoint URLs.
// For the client credentials 2-legged OAuth2 flow, see the clientcredentials
// package (https://golang.org/x/oauth2/clientcredentials).
// For the client credentials 2-legged OAuth2 flow, see the
// [golang.org/x/oauth2/clientcredentials] package.
type Config struct {
// ClientID is the application's ID.
ClientID string
@@ -46,7 +45,7 @@ type Config struct {
// ClientSecret is the application's secret.
ClientSecret string
// Endpoint contains the resource server's token endpoint
// Endpoint contains the authorization server's token endpoint
// URLs. These are constants specific to each server and are
// often available via site-specific packages, such as
// google.Endpoint or github.Endpoint.
@@ -99,7 +98,7 @@ const (
// in the POST body as application/x-www-form-urlencoded parameters.
AuthStyleInParams AuthStyle = 1
// AuthStyleInHeader sends the client_id and client_password
// AuthStyleInHeader sends the client_id and client_secret
// using HTTP Basic Authorization. This is an optional style
// described in the OAuth2 RFC 6749 section 2.3.1.
AuthStyleInHeader AuthStyle = 2
@@ -135,7 +134,7 @@ type setParam struct{ k, v string }
func (p setParam) setValue(m url.Values) { m.Set(p.k, p.v) }
// SetAuthURLParam builds an AuthCodeOption which passes key/value parameters
// SetAuthURLParam builds an [AuthCodeOption] which passes key/value parameters
// to a provider's authorization endpoint.
func SetAuthURLParam(key, value string) AuthCodeOption {
return setParam{key, value}
@@ -148,8 +147,8 @@ func SetAuthURLParam(key, value string) AuthCodeOption {
// request and callback. The authorization server includes this value when
// redirecting the user agent back to the client.
//
// Opts may include AccessTypeOnline or AccessTypeOffline, as well
// as ApprovalForce.
// Opts may include [AccessTypeOnline] or [AccessTypeOffline], as well
// as [ApprovalForce].
//
// To protect against CSRF attacks, opts should include a PKCE challenge
// (S256ChallengeOption). Not all servers support PKCE. An alternative is to
@@ -158,7 +157,7 @@ func SetAuthURLParam(key, value string) AuthCodeOption {
// PKCE), https://www.oauth.com/oauth2-servers/pkce/ and
// https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-09.html#name-cross-site-request-forgery (describing both approaches)
func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string {
var buf bytes.Buffer
var buf strings.Builder
buf.WriteString(c.Endpoint.AuthURL)
v := url.Values{
"response_type": {"code"},
@@ -194,7 +193,7 @@ func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string {
// and when other authorization grant types are not available."
// See https://tools.ietf.org/html/rfc6749#section-4.3 for more info.
//
// The provided context optionally controls which HTTP client is used. See the HTTPClient variable.
// The provided context optionally controls which HTTP client is used. See the [HTTPClient] variable.
func (c *Config) PasswordCredentialsToken(ctx context.Context, username, password string) (*Token, error) {
v := url.Values{
"grant_type": {"password"},
@@ -212,10 +211,10 @@ func (c *Config) PasswordCredentialsToken(ctx context.Context, username, passwor
// It is used after a resource provider redirects the user back
// to the Redirect URI (the URL obtained from AuthCodeURL).
//
// The provided context optionally controls which HTTP client is used. See the HTTPClient variable.
// The provided context optionally controls which HTTP client is used. See the [HTTPClient] variable.
//
// The code will be in the *http.Request.FormValue("code"). Before
// calling Exchange, be sure to validate FormValue("state") if you are
// The code will be in the [http.Request.FormValue]("code"). Before
// calling Exchange, be sure to validate [http.Request.FormValue]("state") if you are
// using it to protect against CSRF attacks.
//
// If using PKCE to protect against CSRF attacks, opts should include a
@@ -242,10 +241,10 @@ func (c *Config) Client(ctx context.Context, t *Token) *http.Client {
return NewClient(ctx, c.TokenSource(ctx, t))
}
// TokenSource returns a TokenSource that returns t until t expires,
// TokenSource returns a [TokenSource] that returns t until t expires,
// automatically refreshing it as necessary using the provided context.
//
// Most users will use Config.Client instead.
// Most users will use [Config.Client] instead.
func (c *Config) TokenSource(ctx context.Context, t *Token) TokenSource {
tkr := &tokenRefresher{
ctx: ctx,
@@ -260,7 +259,7 @@ func (c *Config) TokenSource(ctx context.Context, t *Token) TokenSource {
}
}
// tokenRefresher is a TokenSource that makes "grant_type"=="refresh_token"
// tokenRefresher is a TokenSource that makes "grant_type=refresh_token"
// HTTP requests to renew a token using a RefreshToken.
type tokenRefresher struct {
ctx context.Context // used to get HTTP requests
@@ -305,8 +304,7 @@ type reuseTokenSource struct {
}
// Token returns the current token if it's still valid, else will
// refresh the current token (using r.Context for HTTP client
// information) and return the new one.
// refresh the current token and return the new one.
func (s *reuseTokenSource) Token() (*Token, error) {
s.mu.Lock()
defer s.mu.Unlock()
@@ -322,7 +320,7 @@ func (s *reuseTokenSource) Token() (*Token, error) {
return t, nil
}
// StaticTokenSource returns a TokenSource that always returns the same token.
// StaticTokenSource returns a [TokenSource] that always returns the same token.
// Because the provided token t is never refreshed, StaticTokenSource is only
// useful for tokens that never expire.
func StaticTokenSource(t *Token) TokenSource {
@@ -338,16 +336,16 @@ func (s staticTokenSource) Token() (*Token, error) {
return s.t, nil
}
// HTTPClient is the context key to use with golang.org/x/net/context's
// WithValue function to associate an *http.Client value with a context.
// HTTPClient is the context key to use with [context.WithValue]
// to associate a [*http.Client] value with a context.
var HTTPClient internal.ContextKey
// NewClient creates an *http.Client from a Context and TokenSource.
// NewClient creates an [*http.Client] from a [context.Context] and [TokenSource].
// The returned client is not valid beyond the lifetime of the context.
//
// Note that if a custom *http.Client is provided via the Context it
// Note that if a custom [*http.Client] is provided via the [context.Context] it
// is used only for token acquisition and is not used to configure the
// *http.Client returned from NewClient.
// [*http.Client] returned from NewClient.
//
// As a special case, if src is nil, a non-OAuth2 client is returned
// using the provided context. This exists to support related OAuth2
@@ -368,7 +366,7 @@ func NewClient(ctx context.Context, src TokenSource) *http.Client {
}
}
// ReuseTokenSource returns a TokenSource which repeatedly returns the
// ReuseTokenSource returns a [TokenSource] which repeatedly returns the
// same token as long as it's valid, starting with t.
// When its cached token is invalid, a new token is obtained from src.
//
@@ -376,10 +374,10 @@ func NewClient(ctx context.Context, src TokenSource) *http.Client {
// (such as a file on disk) between runs of a program, rather than
// obtaining new tokens unnecessarily.
//
// The initial token t may be nil, in which case the TokenSource is
// The initial token t may be nil, in which case the [TokenSource] is
// wrapped in a caching version if it isn't one already. This also
// means it's always safe to wrap ReuseTokenSource around any other
// TokenSource without adverse effects.
// [TokenSource] without adverse effects.
func ReuseTokenSource(t *Token, src TokenSource) TokenSource {
// Don't wrap a reuseTokenSource in itself. That would work,
// but cause an unnecessary number of mutex operations.
@@ -397,8 +395,8 @@ func ReuseTokenSource(t *Token, src TokenSource) TokenSource {
}
}
// ReuseTokenSourceWithExpiry returns a TokenSource that acts in the same manner as the
// TokenSource returned by ReuseTokenSource, except the expiry buffer is
// ReuseTokenSourceWithExpiry returns a [TokenSource] that acts in the same manner as the
// [TokenSource] returned by [ReuseTokenSource], except the expiry buffer is
// configurable. The expiration time of a token is calculated as
// t.Expiry.Add(-earlyExpiry).
func ReuseTokenSourceWithExpiry(t *Token, src TokenSource, earlyExpiry time.Duration) TokenSource {

17
vendor/golang.org/x/oauth2/pkce.go generated vendored
View File

@@ -1,6 +1,7 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package oauth2
import (
@@ -20,9 +21,9 @@ const (
// This follows recommendations in RFC 7636.
//
// A fresh verifier should be generated for each authorization.
// S256ChallengeOption(verifier) should then be passed to Config.AuthCodeURL
// (or Config.DeviceAuth) and VerifierOption(verifier) to Config.Exchange
// (or Config.DeviceAccessToken).
// The resulting verifier should be passed to [Config.AuthCodeURL] or [Config.DeviceAuth]
// with [S256ChallengeOption], and to [Config.Exchange] or [Config.DeviceAccessToken]
// with [VerifierOption].
func GenerateVerifier() string {
// "RECOMMENDED that the output of a suitable random number generator be
// used to create a 32-octet sequence. The octet sequence is then
@@ -36,22 +37,22 @@ func GenerateVerifier() string {
return base64.RawURLEncoding.EncodeToString(data)
}
// VerifierOption returns a PKCE code verifier AuthCodeOption. It should be
// passed to Config.Exchange or Config.DeviceAccessToken only.
// VerifierOption returns a PKCE code verifier [AuthCodeOption]. It should only be
// passed to [Config.Exchange] or [Config.DeviceAccessToken].
func VerifierOption(verifier string) AuthCodeOption {
return setParam{k: codeVerifierKey, v: verifier}
}
// S256ChallengeFromVerifier returns a PKCE code challenge derived from verifier with method S256.
//
// Prefer to use S256ChallengeOption where possible.
// Prefer to use [S256ChallengeOption] where possible.
func S256ChallengeFromVerifier(verifier string) string {
sha := sha256.Sum256([]byte(verifier))
return base64.RawURLEncoding.EncodeToString(sha[:])
}
// S256ChallengeOption derives a PKCE code challenge derived from verifier with
// method S256. It should be passed to Config.AuthCodeURL or Config.DeviceAuth
// S256ChallengeOption derives a PKCE code challenge from the verifier with
// method S256. It should be passed to [Config.AuthCodeURL] or [Config.DeviceAuth]
// only.
func S256ChallengeOption(verifier string) AuthCodeOption {
return challengeOption{

19
vendor/golang.org/x/oauth2/token.go generated vendored
View File

@@ -44,7 +44,7 @@ type Token struct {
// Expiry is the optional expiration time of the access token.
//
// If zero, TokenSource implementations will reuse the same
// If zero, [TokenSource] implementations will reuse the same
// token forever and RefreshToken or equivalent
// mechanisms for that TokenSource will not be used.
Expiry time.Time `json:"expiry,omitempty"`
@@ -58,7 +58,7 @@ type Token struct {
// raw optionally contains extra metadata from the server
// when updating a token.
raw interface{}
raw any
// expiryDelta is used to calculate when a token is considered
// expired, by subtracting from Expiry. If zero, defaultExpiryDelta
@@ -86,16 +86,16 @@ func (t *Token) Type() string {
// SetAuthHeader sets the Authorization header to r using the access
// token in t.
//
// This method is unnecessary when using Transport or an HTTP Client
// This method is unnecessary when using [Transport] or an HTTP Client
// returned by this package.
func (t *Token) SetAuthHeader(r *http.Request) {
r.Header.Set("Authorization", t.Type()+" "+t.AccessToken)
}
// WithExtra returns a new Token that's a clone of t, but using the
// WithExtra returns a new [Token] that's a clone of t, but using the
// provided raw extra map. This is only intended for use by packages
// implementing derivative OAuth2 flows.
func (t *Token) WithExtra(extra interface{}) *Token {
func (t *Token) WithExtra(extra any) *Token {
t2 := new(Token)
*t2 = *t
t2.raw = extra
@@ -103,10 +103,10 @@ func (t *Token) WithExtra(extra interface{}) *Token {
}
// Extra returns an extra field.
// Extra fields are key-value pairs returned by the server as a
// Extra fields are key-value pairs returned by the server as
// part of the token retrieval response.
func (t *Token) Extra(key string) interface{} {
if raw, ok := t.raw.(map[string]interface{}); ok {
func (t *Token) Extra(key string) any {
if raw, ok := t.raw.(map[string]any); ok {
return raw[key]
}
@@ -163,13 +163,14 @@ func tokenFromInternal(t *internal.Token) *Token {
TokenType: t.TokenType,
RefreshToken: t.RefreshToken,
Expiry: t.Expiry,
ExpiresIn: t.ExpiresIn,
raw: t.Raw,
}
}
// retrieveToken takes a *Config and uses that to retrieve an *internal.Token.
// This token is then mapped from *internal.Token into an *oauth2.Token which is returned along
// with an error..
// with an error.
func retrieveToken(ctx context.Context, c *Config, v url.Values) (*Token, error) {
tk, err := internal.RetrieveToken(ctx, c.ClientID, c.ClientSecret, c.Endpoint.TokenURL, v, internal.AuthStyle(c.Endpoint.AuthStyle), c.authStyleCache.Get())
if err != nil {

View File

@@ -11,12 +11,12 @@ import (
"sync"
)
// Transport is an http.RoundTripper that makes OAuth 2.0 HTTP requests,
// wrapping a base RoundTripper and adding an Authorization header
// with a token from the supplied Sources.
// Transport is an [http.RoundTripper] that makes OAuth 2.0 HTTP requests,
// wrapping a base [http.RoundTripper] and adding an Authorization header
// with a token from the supplied [TokenSource].
//
// Transport is a low-level mechanism. Most code will use the
// higher-level Config.Client method instead.
// higher-level [Config.Client] method instead.
type Transport struct {
// Source supplies the token to add to outgoing requests'
// Authorization headers.
@@ -47,7 +47,7 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
return nil, err
}
req2 := cloneRequest(req) // per RoundTripper contract
req2 := req.Clone(req.Context())
token.SetAuthHeader(req2)
// req.Body is assumed to be closed by the base RoundTripper.
@@ -58,7 +58,7 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
var cancelOnce sync.Once
// CancelRequest does nothing. It used to be a legacy cancellation mechanism
// but now only it only logs on first use to warn that it's deprecated.
// but now only logs on first use to warn that it's deprecated.
//
// Deprecated: use contexts for cancellation instead.
func (t *Transport) CancelRequest(req *http.Request) {
@@ -73,17 +73,3 @@ func (t *Transport) base() http.RoundTripper {
}
return http.DefaultTransport
}
// cloneRequest returns a clone of the provided *http.Request.
// The clone is a shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
// shallow copy of the struct
r2 := new(http.Request)
*r2 = *r
// deep copy of the Header
r2.Header = make(http.Header, len(r.Header))
for k, s := range r.Header {
r2.Header[k] = append([]string(nil), s...)
}
return r2
}

4
vendor/modules.txt vendored
View File

@@ -641,8 +641,8 @@ golang.org/x/net/internal/httpcommon
golang.org/x/net/internal/httpsfv
golang.org/x/net/internal/timeseries
golang.org/x/net/trace
# golang.org/x/oauth2 v0.28.0
## explicit; go 1.23.0
# golang.org/x/oauth2 v0.35.0
## explicit; go 1.24.0
golang.org/x/oauth2
golang.org/x/oauth2/authhandler
golang.org/x/oauth2/google