google.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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 google provides support for making OAuth2 authorized and
  5. // authenticated HTTP requests to Google APIs.
  6. // It supports the Web server flow, client-side credentials, service accounts,
  7. // Google Compute Engine service accounts, and Google App Engine service
  8. // accounts.
  9. //
  10. // For more information, please read
  11. // https://developers.google.com/accounts/docs/OAuth2
  12. // and
  13. // https://developers.google.com/accounts/docs/application-default-credentials.
  14. package google // import "golang.org/x/oauth2/google"
  15. import (
  16. "encoding/json"
  17. "errors"
  18. "fmt"
  19. "strings"
  20. "time"
  21. "golang.org/x/oauth2"
  22. "golang.org/x/oauth2/jwt"
  23. "google.golang.org/cloud/compute/metadata"
  24. )
  25. // Endpoint is Google's OAuth 2.0 endpoint.
  26. var Endpoint = oauth2.Endpoint{
  27. AuthURL: "https://accounts.google.com/o/oauth2/auth",
  28. TokenURL: "https://accounts.google.com/o/oauth2/token",
  29. }
  30. // JWTTokenURL is Google's OAuth 2.0 token URL to use with the JWT flow.
  31. const JWTTokenURL = "https://accounts.google.com/o/oauth2/token"
  32. // ConfigFromJSON uses a Google Developers Console client_credentials.json
  33. // file to construct a config.
  34. // client_credentials.json can be downloadable from https://console.developers.google.com,
  35. // under "APIs & Auth" > "Credentials". Download the Web application credentials in the
  36. // JSON format and provide the contents of the file as jsonKey.
  37. func ConfigFromJSON(jsonKey []byte, scope ...string) (*oauth2.Config, error) {
  38. type cred struct {
  39. ClientID string `json:"client_id"`
  40. ClientSecret string `json:"client_secret"`
  41. RedirectURIs []string `json:"redirect_uris"`
  42. AuthURI string `json:"auth_uri"`
  43. TokenURI string `json:"token_uri"`
  44. }
  45. var j struct {
  46. Web *cred `json:"web"`
  47. Installed *cred `json:"installed"`
  48. }
  49. if err := json.Unmarshal(jsonKey, &j); err != nil {
  50. return nil, err
  51. }
  52. var c *cred
  53. switch {
  54. case j.Web != nil:
  55. c = j.Web
  56. case j.Installed != nil:
  57. c = j.Installed
  58. default:
  59. return nil, fmt.Errorf("oauth2/google: no credentials found")
  60. }
  61. if len(c.RedirectURIs) < 1 {
  62. return nil, errors.New("oauth2/google: missing redirect URL in the client_credentials.json")
  63. }
  64. return &oauth2.Config{
  65. ClientID: c.ClientID,
  66. ClientSecret: c.ClientSecret,
  67. RedirectURL: c.RedirectURIs[0],
  68. Scopes: scope,
  69. Endpoint: oauth2.Endpoint{
  70. AuthURL: c.AuthURI,
  71. TokenURL: c.TokenURI,
  72. },
  73. }, nil
  74. }
  75. // JWTConfigFromJSON uses a Google Developers service account JSON key file to read
  76. // the credentials that authorize and authenticate the requests.
  77. // Create a service account on "Credentials" page under "APIs & Auth" for your
  78. // project at https://console.developers.google.com to download a JSON key file.
  79. func JWTConfigFromJSON(jsonKey []byte, scope ...string) (*jwt.Config, error) {
  80. var key struct {
  81. Email string `json:"client_email"`
  82. PrivateKey string `json:"private_key"`
  83. }
  84. if err := json.Unmarshal(jsonKey, &key); err != nil {
  85. return nil, err
  86. }
  87. return &jwt.Config{
  88. Email: key.Email,
  89. PrivateKey: []byte(key.PrivateKey),
  90. Scopes: scope,
  91. TokenURL: JWTTokenURL,
  92. }, nil
  93. }
  94. // ComputeTokenSource returns a token source that fetches access tokens
  95. // from Google Compute Engine (GCE)'s metadata server. It's only valid to use
  96. // this token source if your program is running on a GCE instance.
  97. // If no account is specified, "default" is used.
  98. // Further information about retrieving access tokens from the GCE metadata
  99. // server can be found at https://cloud.google.com/compute/docs/authentication.
  100. func ComputeTokenSource(account string) oauth2.TokenSource {
  101. return oauth2.ReuseTokenSource(nil, computeSource{account: account})
  102. }
  103. type computeSource struct {
  104. account string
  105. }
  106. func (cs computeSource) Token() (*oauth2.Token, error) {
  107. if !metadata.OnGCE() {
  108. return nil, errors.New("oauth2/google: can't get a token from the metadata service; not running on GCE")
  109. }
  110. acct := cs.account
  111. if acct == "" {
  112. acct = "default"
  113. }
  114. tokenJSON, err := metadata.Get("instance/service-accounts/" + acct + "/token")
  115. if err != nil {
  116. return nil, err
  117. }
  118. var res struct {
  119. AccessToken string `json:"access_token"`
  120. ExpiresInSec int `json:"expires_in"`
  121. TokenType string `json:"token_type"`
  122. }
  123. err = json.NewDecoder(strings.NewReader(tokenJSON)).Decode(&res)
  124. if err != nil {
  125. return nil, fmt.Errorf("oauth2/google: invalid token JSON from metadata: %v", err)
  126. }
  127. if res.ExpiresInSec == 0 || res.AccessToken == "" {
  128. return nil, fmt.Errorf("oauth2/google: incomplete token received from metadata")
  129. }
  130. return &oauth2.Token{
  131. AccessToken: res.AccessToken,
  132. TokenType: res.TokenType,
  133. Expiry: time.Now().Add(time.Duration(res.ExpiresInSec) * time.Second),
  134. }, nil
  135. }