clientcredentials.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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. "context"
  16. "fmt"
  17. "net/http"
  18. "net/url"
  19. "strings"
  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. // Scopes specifies optional requested permissions.
  34. Scopes []string
  35. // EndpointParams specifies additional parameters for requests to the token endpoint.
  36. EndpointParams url.Values
  37. // AuthStyle optionally specifies how the endpoint wants the
  38. // client ID & client secret sent. The zero value means to
  39. // auto-detect.
  40. AuthStyle oauth2.AuthStyle
  41. // authStyleCache caches which auth style to use when Endpoint.AuthStyle is
  42. // the zero value (AuthStyleAutoDetect).
  43. authStyleCache internal.LazyAuthStyleCache
  44. }
  45. // Token uses client credentials to retrieve a token.
  46. //
  47. // The provided context optionally controls which HTTP client is used. See the [oauth2.HTTPClient] variable.
  48. func (c *Config) Token(ctx context.Context) (*oauth2.Token, error) {
  49. return c.TokenSource(ctx).Token()
  50. }
  51. // Client returns an HTTP client using the provided token.
  52. // The token will auto-refresh as necessary.
  53. //
  54. // The provided context optionally controls which HTTP client
  55. // is returned. See the [oauth2.HTTPClient] variable.
  56. //
  57. // The returned [http.Client] and its Transport should not be modified.
  58. func (c *Config) Client(ctx context.Context) *http.Client {
  59. return oauth2.NewClient(ctx, c.TokenSource(ctx))
  60. }
  61. // TokenSource returns a [oauth2.TokenSource] that returns t until t expires,
  62. // automatically refreshing it as necessary using the provided context and the
  63. // client ID and client secret.
  64. //
  65. // Most users will use [Config.Client] instead.
  66. func (c *Config) TokenSource(ctx context.Context) oauth2.TokenSource {
  67. source := &tokenSource{
  68. ctx: ctx,
  69. conf: c,
  70. }
  71. return oauth2.ReuseTokenSource(nil, source)
  72. }
  73. type tokenSource struct {
  74. ctx context.Context
  75. conf *Config
  76. }
  77. // Token refreshes the token by using a new client credentials request.
  78. // tokens received this way do not include a refresh token
  79. func (c *tokenSource) Token() (*oauth2.Token, error) {
  80. v := url.Values{
  81. "grant_type": {"client_credentials"},
  82. }
  83. if len(c.conf.Scopes) > 0 {
  84. v.Set("scope", strings.Join(c.conf.Scopes, " "))
  85. }
  86. for k, p := range c.conf.EndpointParams {
  87. // Allow grant_type to be overridden to allow interoperability with
  88. // non-compliant implementations.
  89. if _, ok := v[k]; ok && k != "grant_type" {
  90. return nil, fmt.Errorf("oauth2: cannot overwrite parameter %q", k)
  91. }
  92. v[k] = p
  93. }
  94. tk, err := internal.RetrieveToken(c.ctx, c.conf.ClientID, c.conf.ClientSecret, c.conf.TokenURL, v, internal.AuthStyle(c.conf.AuthStyle), c.conf.authStyleCache.Get())
  95. if err != nil {
  96. if rErr, ok := err.(*internal.RetrieveError); ok {
  97. return nil, (*oauth2.RetrieveError)(rErr)
  98. }
  99. return nil, err
  100. }
  101. t := &oauth2.Token{
  102. AccessToken: tk.AccessToken,
  103. TokenType: tk.TokenType,
  104. RefreshToken: tk.RefreshToken,
  105. Expiry: tk.Expiry,
  106. }
  107. return t.WithExtra(tk.Raw), nil
  108. }