Source File
oauth2.go
Belonging Package
golang.org/x/oauth2
// Copyright 2014 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 provides support for making// OAuth2 authorized and authenticated HTTP requests,// as specified in RFC 6749.// It can additionally grant authorization with Bearer JWT.package oauth2 // import "golang.org/x/oauth2"import ()// NoContext is the default context you should supply if not using// your own [context.Context].//// Deprecated: Use [context.Background] or [context.TODO] instead.var NoContext = context.TODO()// 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 ( 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// [golang.org/x/oauth2/clientcredentials] package.type Config struct {// ClientID is the application's ID.ClientID string// ClientSecret is the application's secret.ClientSecret string// 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.Endpoint Endpoint// RedirectURL is the URL to redirect users going through// the OAuth flow, after the resource owner's URLs.RedirectURL string// Scopes specifies optional requested permissions.Scopes []string// authStyleCache caches which auth style to use when Endpoint.AuthStyle is// the zero value (AuthStyleAutoDetect).authStyleCache internal.LazyAuthStyleCache}// A TokenSource is anything that can return a token.type TokenSource interface {// Token returns a token or an error.// Token must be safe for concurrent use by multiple goroutines.// The returned Token must not be modified.Token() (*Token, error)}// Endpoint represents an OAuth 2.0 provider's authorization and token// endpoint URLs.type Endpoint struct {AuthURL stringDeviceAuthURL stringTokenURL string// AuthStyle optionally specifies how the endpoint wants the// client ID & client secret sent. The zero value means to// auto-detect.AuthStyle AuthStyle}// AuthStyle represents how requests for tokens are authenticated// to the server.type AuthStyle intconst (// AuthStyleAutoDetect means to auto-detect which authentication// style the provider wants by trying both ways and caching// the successful way for the future.AuthStyleAutoDetect AuthStyle = 0// AuthStyleInParams sends the "client_id" and "client_secret"// in the POST body as application/x-www-form-urlencoded parameters.AuthStyleInParams AuthStyle = 1// AuthStyleInHeader sends the client_id and client_password// using HTTP Basic Authorization. This is an optional style// described in the OAuth2 RFC 6749 section 2.3.1.AuthStyleInHeader AuthStyle = 2)var (// AccessTypeOnline and AccessTypeOffline are options passed// to the Options.AuthCodeURL method. They modify the// "access_type" field that gets sent in the URL returned by// AuthCodeURL.//// Online is the default if neither is specified. If your// application needs to refresh access tokens when the user// is not present at the browser, then use offline. This will// result in your application obtaining a refresh token the// first time your application exchanges an authorization// code for a user.AccessTypeOnline AuthCodeOption = SetAuthURLParam("access_type", "online")AccessTypeOffline AuthCodeOption = SetAuthURLParam("access_type", "offline")// ApprovalForce forces the users to view the consent dialog// and confirm the permissions request at the URL returned// from AuthCodeURL, even if they've already done so.ApprovalForce AuthCodeOption = SetAuthURLParam("prompt", "consent"))// An AuthCodeOption is passed to Config.AuthCodeURL.type AuthCodeOption interface {setValue(url.Values)}type setParam struct{ k, v string }func ( setParam) ( url.Values) { .Set(.k, .v) }// SetAuthURLParam builds an [AuthCodeOption] which passes key/value parameters// to a provider's authorization endpoint.func (, string) AuthCodeOption {return setParam{, }}// AuthCodeURL returns a URL to OAuth 2.0 provider's consent page// that asks for permissions for the required scopes explicitly.//// State is an opaque value used by the client to maintain state between the// 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].//// To protect against CSRF attacks, opts should include a PKCE challenge// (S256ChallengeOption). Not all servers support PKCE. An alternative is to// generate a random state parameter and verify it after exchange.// See https://datatracker.ietf.org/doc/html/rfc6749#section-10.12 (predating// 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 ( *Config) ( string, ...AuthCodeOption) string {var bytes.Buffer.WriteString(.Endpoint.AuthURL):= url.Values{"response_type": {"code"},"client_id": {.ClientID},}if .RedirectURL != "" {.Set("redirect_uri", .RedirectURL)}if len(.Scopes) > 0 {.Set("scope", strings.Join(.Scopes, " "))}if != "" {.Set("state", )}for , := range {.setValue()}if strings.Contains(.Endpoint.AuthURL, "?") {.WriteByte('&')} else {.WriteByte('?')}.WriteString(.Encode())return .String()}// PasswordCredentialsToken converts a resource owner username and password// pair into a token.//// Per the RFC, this grant type should only be used "when there is a high// degree of trust between the resource owner and the client (e.g., the client// is part of the device operating system or a highly privileged application),// 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.func ( *Config) ( context.Context, , string) (*Token, error) {:= url.Values{"grant_type": {"password"},"username": {},"password": {},}if len(.Scopes) > 0 {.Set("scope", strings.Join(.Scopes, " "))}return retrieveToken(, , )}// Exchange converts an authorization code into a token.//// 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 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// VerifierOption.func ( *Config) ( context.Context, string, ...AuthCodeOption) (*Token, error) {:= url.Values{"grant_type": {"authorization_code"},"code": {},}if .RedirectURL != "" {.Set("redirect_uri", .RedirectURL)}for , := range {.setValue()}return retrieveToken(, , )}// Client returns an HTTP client using the provided token.// The token will auto-refresh as necessary. The underlying// HTTP transport will be obtained using the provided context.// The returned client and its Transport should not be modified.func ( *Config) ( context.Context, *Token) *http.Client {return NewClient(, .TokenSource(, ))}// 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.func ( *Config) ( context.Context, *Token) TokenSource {:= &tokenRefresher{ctx: ,conf: ,}if != nil {.refreshToken = .RefreshToken}return &reuseTokenSource{t: ,new: ,}}// 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 requestsconf *ConfigrefreshToken string}// WARNING: Token is not safe for concurrent access, as it// updates the tokenRefresher's refreshToken field.// Within this package, it is used by reuseTokenSource which// synchronizes calls to this method with its own mutex.func ( *tokenRefresher) () (*Token, error) {if .refreshToken == "" {return nil, errors.New("oauth2: token expired and refresh token is not set")}, := retrieveToken(.ctx, .conf, url.Values{"grant_type": {"refresh_token"},"refresh_token": {.refreshToken},})if != nil {return nil,}if .refreshToken != .RefreshToken {.refreshToken = .RefreshToken}return , nil}// reuseTokenSource is a TokenSource that holds a single token in memory// and validates its expiry before each call to retrieve it with// Token. If it's expired, it will be auto-refreshed using the// new TokenSource.type reuseTokenSource struct {new TokenSource // called when t is expired.mu sync.Mutex // guards tt *TokenexpiryDelta time.Duration}// Token returns the current token if it's still valid, else will// refresh the current token and return the new one.func ( *reuseTokenSource) () (*Token, error) {.mu.Lock()defer .mu.Unlock()if .t.Valid() {return .t, nil}, := .new.Token()if != nil {return nil,}.expiryDelta = .expiryDelta.t =return , nil}// 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 ( *Token) TokenSource {return staticTokenSource{}}// staticTokenSource is a TokenSource that always returns the same Token.type staticTokenSource struct {t *Token}func ( staticTokenSource) () (*Token, error) {return .t, nil}// 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.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.Context] it// is used only for token acquisition and is not used to configure the// [*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// packages.func ( context.Context, TokenSource) *http.Client {if == nil {return internal.ContextClient()}:= internal.ContextClient()return &http.Client{Transport: &Transport{Base: .Transport,Source: ReuseTokenSource(nil, ),},CheckRedirect: .CheckRedirect,Jar: .Jar,Timeout: .Timeout,}}// 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.//// ReuseTokenSource is typically used to reuse tokens from a cache// (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// 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.func ( *Token, TokenSource) TokenSource {// Don't wrap a reuseTokenSource in itself. That would work,// but cause an unnecessary number of mutex operations.// Just build the equivalent one.if , := .(*reuseTokenSource); {if == nil {// Just use it directly.return}= .new}return &reuseTokenSource{t: ,new: ,}}// 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 ( *Token, TokenSource, time.Duration) TokenSource {// Don't wrap a reuseTokenSource in itself. That would work,// but cause an unnecessary number of mutex operations.// Just build the equivalent one.if , := .(*reuseTokenSource); {if == nil {// Just use it directly, but set the expiryDelta to earlyExpiry,// so the behavior matches what the user expects..expiryDelta =return}= .new}if != nil {.expiryDelta =}return &reuseTokenSource{t: ,new: ,expiryDelta: ,}}
![]() |
The pages are generated with Golds v0.8.2. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |