1// Copyright 2014 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// Package oauth2 provides support for making 6// OAuth2 authorized and authenticated HTTP requests, 7// as specified in RFC 6749. 8// It can additionally grant authorization with Bearer JWT. 9package oauth2 // import "golang.org/x/oauth2" 10 11import ( 12 "bytes" 13 "errors" 14 "net/http" 15 "net/url" 16 "strings" 17 "sync" 18 19 "golang.org/x/net/context" 20 "golang.org/x/oauth2/internal" 21) 22 23// NoContext is the default context you should supply if not using 24// your own context.Context (see https://golang.org/x/net/context). 25// 26// Deprecated: Use context.Background() or context.TODO() instead. 27var NoContext = context.TODO() 28 29// RegisterBrokenAuthHeaderProvider registers an OAuth2 server 30// identified by the tokenURL prefix as an OAuth2 implementation 31// which doesn't support the HTTP Basic authentication 32// scheme to authenticate with the authorization server. 33// Once a server is registered, credentials (client_id and client_secret) 34// will be passed as query parameters rather than being present 35// in the Authorization header. 36// See https://code.google.com/p/goauth2/issues/detail?id=31 for background. 37func RegisterBrokenAuthHeaderProvider(tokenURL string) { 38 internal.RegisterBrokenAuthHeaderProvider(tokenURL) 39} 40 41// Config describes a typical 3-legged OAuth2 flow, with both the 42// client application information and the server's endpoint URLs. 43// For the client credentials 2-legged OAuth2 flow, see the clientcredentials 44// package (https://golang.org/x/oauth2/clientcredentials). 45type Config struct { 46 // ClientID is the application's ID. 47 ClientID string 48 49 // ClientSecret is the application's secret. 50 ClientSecret string 51 52 // Endpoint contains the resource server's token endpoint 53 // URLs. These are constants specific to each server and are 54 // often available via site-specific packages, such as 55 // google.Endpoint or github.Endpoint. 56 Endpoint Endpoint 57 58 // RedirectURL is the URL to redirect users going through 59 // the OAuth flow, after the resource owner's URLs. 60 RedirectURL string 61 62 // Scope specifies optional requested permissions. 63 Scopes []string 64} 65 66// A TokenSource is anything that can return a token. 67type TokenSource interface { 68 // Token returns a token or an error. 69 // Token must be safe for concurrent use by multiple goroutines. 70 // The returned Token must not be modified. 71 Token() (*Token, error) 72} 73 74// Endpoint contains the OAuth 2.0 provider's authorization and token 75// endpoint URLs. 76type Endpoint struct { 77 AuthURL string 78 TokenURL string 79} 80 81var ( 82 // AccessTypeOnline and AccessTypeOffline are options passed 83 // to the Options.AuthCodeURL method. They modify the 84 // "access_type" field that gets sent in the URL returned by 85 // AuthCodeURL. 86 // 87 // Online is the default if neither is specified. If your 88 // application needs to refresh access tokens when the user 89 // is not present at the browser, then use offline. This will 90 // result in your application obtaining a refresh token the 91 // first time your application exchanges an authorization 92 // code for a user. 93 AccessTypeOnline AuthCodeOption = SetAuthURLParam("access_type", "online") 94 AccessTypeOffline AuthCodeOption = SetAuthURLParam("access_type", "offline") 95 96 // ApprovalForce forces the users to view the consent dialog 97 // and confirm the permissions request at the URL returned 98 // from AuthCodeURL, even if they've already done so. 99 ApprovalForce AuthCodeOption = SetAuthURLParam("approval_prompt", "force") 100) 101 102// An AuthCodeOption is passed to Config.AuthCodeURL. 103type AuthCodeOption interface { 104 setValue(url.Values) 105} 106 107type setParam struct{ k, v string } 108 109func (p setParam) setValue(m url.Values) { m.Set(p.k, p.v) } 110 111// SetAuthURLParam builds an AuthCodeOption which passes key/value parameters 112// to a provider's authorization endpoint. 113func SetAuthURLParam(key, value string) AuthCodeOption { 114 return setParam{key, value} 115} 116 117// AuthCodeURL returns a URL to OAuth 2.0 provider's consent page 118// that asks for permissions for the required scopes explicitly. 119// 120// State is a token to protect the user from CSRF attacks. You must 121// always provide a non-empty string and validate that it matches the 122// the state query parameter on your redirect callback. 123// See http://tools.ietf.org/html/rfc6749#section-10.12 for more info. 124// 125// Opts may include AccessTypeOnline or AccessTypeOffline, as well 126// as ApprovalForce. 127// It can also be used to pass the PKCE challange. 128// See https://www.oauth.com/oauth2-servers/pkce/ for more info. 129func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string { 130 var buf bytes.Buffer 131 buf.WriteString(c.Endpoint.AuthURL) 132 v := url.Values{ 133 "response_type": {"code"}, 134 "client_id": {c.ClientID}, 135 } 136 if c.RedirectURL != "" { 137 v.Set("redirect_uri", c.RedirectURL) 138 } 139 if len(c.Scopes) > 0 { 140 v.Set("scope", strings.Join(c.Scopes, " ")) 141 } 142 if state != "" { 143 // TODO(light): Docs say never to omit state; don't allow empty. 144 v.Set("state", state) 145 } 146 for _, opt := range opts { 147 opt.setValue(v) 148 } 149 if strings.Contains(c.Endpoint.AuthURL, "?") { 150 buf.WriteByte('&') 151 } else { 152 buf.WriteByte('?') 153 } 154 buf.WriteString(v.Encode()) 155 return buf.String() 156} 157 158// PasswordCredentialsToken converts a resource owner username and password 159// pair into a token. 160// 161// Per the RFC, this grant type should only be used "when there is a high 162// degree of trust between the resource owner and the client (e.g., the client 163// is part of the device operating system or a highly privileged application), 164// and when other authorization grant types are not available." 165// See https://tools.ietf.org/html/rfc6749#section-4.3 for more info. 166// 167// The HTTP client to use is derived from the context. 168// If nil, http.DefaultClient is used. 169func (c *Config) PasswordCredentialsToken(ctx context.Context, username, password string) (*Token, error) { 170 v := url.Values{ 171 "grant_type": {"password"}, 172 "username": {username}, 173 "password": {password}, 174 } 175 if len(c.Scopes) > 0 { 176 v.Set("scope", strings.Join(c.Scopes, " ")) 177 } 178 return retrieveToken(ctx, c, v) 179} 180 181// Exchange converts an authorization code into a token. 182// 183// It is used after a resource provider redirects the user back 184// to the Redirect URI (the URL obtained from AuthCodeURL). 185// 186// The HTTP client to use is derived from the context. 187// If a client is not provided via the context, http.DefaultClient is used. 188// 189// The code will be in the *http.Request.FormValue("code"). Before 190// calling Exchange, be sure to validate FormValue("state"). 191// 192// Opts may include the PKCE verifier code if previously used in AuthCodeURL. 193// See https://www.oauth.com/oauth2-servers/pkce/ for more info. 194func (c *Config) Exchange(ctx context.Context, code string, opts ...AuthCodeOption) (*Token, error) { 195 v := url.Values{ 196 "grant_type": {"authorization_code"}, 197 "code": {code}, 198 } 199 if c.RedirectURL != "" { 200 v.Set("redirect_uri", c.RedirectURL) 201 } 202 for _, opt := range opts { 203 opt.setValue(v) 204 } 205 return retrieveToken(ctx, c, v) 206} 207 208// Client returns an HTTP client using the provided token. 209// The token will auto-refresh as necessary. The underlying 210// HTTP transport will be obtained using the provided context. 211// The returned client and its Transport should not be modified. 212func (c *Config) Client(ctx context.Context, t *Token) *http.Client { 213 return NewClient(ctx, c.TokenSource(ctx, t)) 214} 215 216// TokenSource returns a TokenSource that returns t until t expires, 217// automatically refreshing it as necessary using the provided context. 218// 219// Most users will use Config.Client instead. 220func (c *Config) TokenSource(ctx context.Context, t *Token) TokenSource { 221 tkr := &tokenRefresher{ 222 ctx: ctx, 223 conf: c, 224 } 225 if t != nil { 226 tkr.refreshToken = t.RefreshToken 227 } 228 return &reuseTokenSource{ 229 t: t, 230 new: tkr, 231 } 232} 233 234// tokenRefresher is a TokenSource that makes "grant_type"=="refresh_token" 235// HTTP requests to renew a token using a RefreshToken. 236type tokenRefresher struct { 237 ctx context.Context // used to get HTTP requests 238 conf *Config 239 refreshToken string 240} 241 242// WARNING: Token is not safe for concurrent access, as it 243// updates the tokenRefresher's refreshToken field. 244// Within this package, it is used by reuseTokenSource which 245// synchronizes calls to this method with its own mutex. 246func (tf *tokenRefresher) Token() (*Token, error) { 247 if tf.refreshToken == "" { 248 return nil, errors.New("oauth2: token expired and refresh token is not set") 249 } 250 251 tk, err := retrieveToken(tf.ctx, tf.conf, url.Values{ 252 "grant_type": {"refresh_token"}, 253 "refresh_token": {tf.refreshToken}, 254 }) 255 256 if err != nil { 257 return nil, err 258 } 259 if tf.refreshToken != tk.RefreshToken { 260 tf.refreshToken = tk.RefreshToken 261 } 262 return tk, err 263} 264 265// reuseTokenSource is a TokenSource that holds a single token in memory 266// and validates its expiry before each call to retrieve it with 267// Token. If it's expired, it will be auto-refreshed using the 268// new TokenSource. 269type reuseTokenSource struct { 270 new TokenSource // called when t is expired. 271 272 mu sync.Mutex // guards t 273 t *Token 274} 275 276// Token returns the current token if it's still valid, else will 277// refresh the current token (using r.Context for HTTP client 278// information) and return the new one. 279func (s *reuseTokenSource) Token() (*Token, error) { 280 s.mu.Lock() 281 defer s.mu.Unlock() 282 if s.t.Valid() { 283 return s.t, nil 284 } 285 t, err := s.new.Token() 286 if err != nil { 287 return nil, err 288 } 289 s.t = t 290 return t, nil 291} 292 293// StaticTokenSource returns a TokenSource that always returns the same token. 294// Because the provided token t is never refreshed, StaticTokenSource is only 295// useful for tokens that never expire. 296func StaticTokenSource(t *Token) TokenSource { 297 return staticTokenSource{t} 298} 299 300// staticTokenSource is a TokenSource that always returns the same Token. 301type staticTokenSource struct { 302 t *Token 303} 304 305func (s staticTokenSource) Token() (*Token, error) { 306 return s.t, nil 307} 308 309// HTTPClient is the context key to use with golang.org/x/net/context's 310// WithValue function to associate an *http.Client value with a context. 311var HTTPClient internal.ContextKey 312 313// NewClient creates an *http.Client from a Context and TokenSource. 314// The returned client is not valid beyond the lifetime of the context. 315// 316// Note that if a custom *http.Client is provided via the Context it 317// is used only for token acquisition and is not used to configure the 318// *http.Client returned from NewClient. 319// 320// As a special case, if src is nil, a non-OAuth2 client is returned 321// using the provided context. This exists to support related OAuth2 322// packages. 323func NewClient(ctx context.Context, src TokenSource) *http.Client { 324 if src == nil { 325 return internal.ContextClient(ctx) 326 } 327 return &http.Client{ 328 Transport: &Transport{ 329 Base: internal.ContextClient(ctx).Transport, 330 Source: ReuseTokenSource(nil, src), 331 }, 332 } 333} 334 335// ReuseTokenSource returns a TokenSource which repeatedly returns the 336// same token as long as it's valid, starting with t. 337// When its cached token is invalid, a new token is obtained from src. 338// 339// ReuseTokenSource is typically used to reuse tokens from a cache 340// (such as a file on disk) between runs of a program, rather than 341// obtaining new tokens unnecessarily. 342// 343// The initial token t may be nil, in which case the TokenSource is 344// wrapped in a caching version if it isn't one already. This also 345// means it's always safe to wrap ReuseTokenSource around any other 346// TokenSource without adverse effects. 347func ReuseTokenSource(t *Token, src TokenSource) TokenSource { 348 // Don't wrap a reuseTokenSource in itself. That would work, 349 // but cause an unnecessary number of mutex operations. 350 // Just build the equivalent one. 351 if rt, ok := src.(*reuseTokenSource); ok { 352 if t == nil { 353 // Just use it directly. 354 return rt 355 } 356 src = rt.new 357 } 358 return &reuseTokenSource{ 359 t: t, 360 new: src, 361 } 362} 363