mirror of
https://github.com/golang/oauth2.git
synced 2025-07-21 00:00:09 +08:00
Instead of maintaining a global map of which OAuth2 servers do which auth style and/or requiring the user to tell us, just try both ways and remember which way worked. But if users want to tell us in the Endpoint, this CL also add Endpoint.AuthStyle. Fixes golang/oauth2#111 Fixes golang/oauth2#365 Fixes golang/oauth2#362 Fixes golang/oauth2#357 Fixes golang/oauth2#353 Fixes golang/oauth2#345 Fixes golang/oauth2#326 Fixes golang/oauth2#352 Fixes golang/oauth2#268 Fixes https://go-review.googlesource.com/c/oauth2/+/58510 (... and surely many more ...) Change-Id: I7b4d98ba1900ee2d3e11e629316b0bf867f7d237 Reviewed-on: https://go-review.googlesource.com/c/157820 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ross Light <light@google.com>
121 lines
3.7 KiB
Go
121 lines
3.7 KiB
Go
// 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 clientcredentials implements the OAuth2.0 "client credentials" token flow,
|
|
// also known as the "two-legged OAuth 2.0".
|
|
//
|
|
// This should be used when the client is acting on its own behalf or when the client
|
|
// is the resource owner. It may also be used when requesting access to protected
|
|
// resources based on an authorization previously arranged with the authorization
|
|
// server.
|
|
//
|
|
// See https://tools.ietf.org/html/rfc6749#section-4.4
|
|
package clientcredentials // import "golang.org/x/oauth2/clientcredentials"
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
|
|
"golang.org/x/oauth2"
|
|
"golang.org/x/oauth2/internal"
|
|
)
|
|
|
|
// Config describes a 2-legged OAuth2 flow, with both the
|
|
// client application information and the server's endpoint URLs.
|
|
type Config struct {
|
|
// ClientID is the application's ID.
|
|
ClientID string
|
|
|
|
// ClientSecret is the application's secret.
|
|
ClientSecret string
|
|
|
|
// TokenURL is the resource server's token endpoint
|
|
// URL. This is a constant specific to each server.
|
|
TokenURL string
|
|
|
|
// Scope specifies optional requested permissions.
|
|
Scopes []string
|
|
|
|
// EndpointParams specifies additional parameters for requests to the token endpoint.
|
|
EndpointParams url.Values
|
|
|
|
// AuthStyle optionally specifies how the endpoint wants the
|
|
// client ID & client secret sent. The zero value means to
|
|
// auto-detect.
|
|
AuthStyle oauth2.AuthStyle
|
|
}
|
|
|
|
// Token uses client credentials to retrieve a token.
|
|
//
|
|
// The provided context optionally controls which HTTP client is used. See the oauth2.HTTPClient variable.
|
|
func (c *Config) Token(ctx context.Context) (*oauth2.Token, error) {
|
|
return c.TokenSource(ctx).Token()
|
|
}
|
|
|
|
// Client returns an HTTP client using the provided token.
|
|
// The token will auto-refresh as necessary.
|
|
//
|
|
// The provided context optionally controls which HTTP client
|
|
// is returned. See the oauth2.HTTPClient variable.
|
|
//
|
|
// The returned Client and its Transport should not be modified.
|
|
func (c *Config) Client(ctx context.Context) *http.Client {
|
|
return oauth2.NewClient(ctx, c.TokenSource(ctx))
|
|
}
|
|
|
|
// TokenSource returns a TokenSource that returns t until t expires,
|
|
// automatically refreshing it as necessary using the provided context and the
|
|
// client ID and client secret.
|
|
//
|
|
// Most users will use Config.Client instead.
|
|
func (c *Config) TokenSource(ctx context.Context) oauth2.TokenSource {
|
|
source := &tokenSource{
|
|
ctx: ctx,
|
|
conf: c,
|
|
}
|
|
return oauth2.ReuseTokenSource(nil, source)
|
|
}
|
|
|
|
type tokenSource struct {
|
|
ctx context.Context
|
|
conf *Config
|
|
}
|
|
|
|
// Token refreshes the token by using a new client credentials request.
|
|
// tokens received this way do not include a refresh token
|
|
func (c *tokenSource) Token() (*oauth2.Token, error) {
|
|
v := url.Values{
|
|
"grant_type": {"client_credentials"},
|
|
}
|
|
if len(c.conf.Scopes) > 0 {
|
|
v.Set("scope", strings.Join(c.conf.Scopes, " "))
|
|
}
|
|
for k, p := range c.conf.EndpointParams {
|
|
// Allow grant_type to be overridden to allow interoperability with
|
|
// non-compliant implementations.
|
|
if _, ok := v[k]; ok && k != "grant_type" {
|
|
return nil, fmt.Errorf("oauth2: cannot overwrite parameter %q", k)
|
|
}
|
|
v[k] = p
|
|
}
|
|
|
|
tk, err := internal.RetrieveToken(c.ctx, c.conf.ClientID, c.conf.ClientSecret, c.conf.TokenURL, v, internal.AuthStyle(c.conf.AuthStyle))
|
|
if err != nil {
|
|
if rErr, ok := err.(*internal.RetrieveError); ok {
|
|
return nil, (*oauth2.RetrieveError)(rErr)
|
|
}
|
|
return nil, err
|
|
}
|
|
t := &oauth2.Token{
|
|
AccessToken: tk.AccessToken,
|
|
TokenType: tk.TokenType,
|
|
RefreshToken: tk.RefreshToken,
|
|
Expiry: tk.Expiry,
|
|
}
|
|
return t.WithExtra(tk.Raw), nil
|
|
}
|