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