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