You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

110 lines
3.3 KiB

  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. // Package clientcredentials implements the OAuth2.0 "client credentials" token flow,
  5. // also known as the "two-legged OAuth 2.0".
  6. //
  7. // This should be used when the client is acting on its own behalf or when the client
  8. // is the resource owner. It may also be used when requesting access to protected
  9. // resources based on an authorization previously arranged with the authorization
  10. // server.
  11. //
  12. // See https://tools.ietf.org/html/rfc6749#section-4.4
  13. package clientcredentials // import "golang.org/x/oauth2/clientcredentials"
  14. import (
  15. "fmt"
  16. "net/http"
  17. "net/url"
  18. "strings"
  19. "golang.org/x/net/context"
  20. "golang.org/x/oauth2"
  21. "golang.org/x/oauth2/internal"
  22. )
  23. // Config describes a 2-legged OAuth2 flow, with both the
  24. // client application information and the server's endpoint URLs.
  25. type Config struct {
  26. // ClientID is the application's ID.
  27. ClientID string
  28. // ClientSecret is the application's secret.
  29. ClientSecret string
  30. // TokenURL is the resource server's token endpoint
  31. // URL. This is a constant specific to each server.
  32. TokenURL string
  33. // Scope specifies optional requested permissions.
  34. Scopes []string
  35. // EndpointParams specifies additional parameters for requests to the token endpoint.
  36. EndpointParams url.Values
  37. }
  38. // Token uses client credentials to retrieve a token.
  39. // The HTTP client to use is derived from the context.
  40. // If nil, http.DefaultClient is used.
  41. func (c *Config) Token(ctx context.Context) (*oauth2.Token, error) {
  42. return c.TokenSource(ctx).Token()
  43. }
  44. // Client returns an HTTP client using the provided token.
  45. // The token will auto-refresh as necessary. The underlying
  46. // HTTP transport will be obtained using the provided context.
  47. // The returned client and its Transport should not be modified.
  48. func (c *Config) Client(ctx context.Context) *http.Client {
  49. return oauth2.NewClient(ctx, c.TokenSource(ctx))
  50. }
  51. // TokenSource returns a TokenSource that returns t until t expires,
  52. // automatically refreshing it as necessary using the provided context and the
  53. // client ID and client secret.
  54. //
  55. // Most users will use Config.Client instead.
  56. func (c *Config) TokenSource(ctx context.Context) oauth2.TokenSource {
  57. source := &tokenSource{
  58. ctx: ctx,
  59. conf: c,
  60. }
  61. return oauth2.ReuseTokenSource(nil, source)
  62. }
  63. type tokenSource struct {
  64. ctx context.Context
  65. conf *Config
  66. }
  67. // Token refreshes the token by using a new client credentials request.
  68. // tokens received this way do not include a refresh token
  69. func (c *tokenSource) Token() (*oauth2.Token, error) {
  70. v := url.Values{
  71. "grant_type": {"client_credentials"},
  72. }
  73. if len(c.conf.Scopes) > 0 {
  74. v.Set("scope", strings.Join(c.conf.Scopes, " "))
  75. }
  76. for k, p := range c.conf.EndpointParams {
  77. if _, ok := v[k]; ok {
  78. return nil, fmt.Errorf("oauth2: cannot overwrite parameter %q", k)
  79. }
  80. v[k] = p
  81. }
  82. tk, err := internal.RetrieveToken(c.ctx, c.conf.ClientID, c.conf.ClientSecret, c.conf.TokenURL, v)
  83. if err != nil {
  84. if rErr, ok := err.(*internal.RetrieveError); ok {
  85. return nil, (*oauth2.RetrieveError)(rErr)
  86. }
  87. return nil, err
  88. }
  89. t := &oauth2.Token{
  90. AccessToken: tk.AccessToken,
  91. TokenType: tk.TokenType,
  92. RefreshToken: tk.RefreshToken,
  93. Expiry: tk.Expiry,
  94. }
  95. return t.WithExtra(tk.Raw), nil
  96. }