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.
 
 
 

75 lines
2.1 KiB

  1. // Copyright 2015 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
  5. import (
  6. "crypto/rsa"
  7. "fmt"
  8. "time"
  9. "golang.org/x/oauth2"
  10. "golang.org/x/oauth2/internal"
  11. "golang.org/x/oauth2/jws"
  12. )
  13. // JWTAccessTokenSourceFromJSON uses a Google Developers service account JSON
  14. // key file to read the credentials that authorize and authenticate the
  15. // requests, and returns a TokenSource that does not use any OAuth2 flow but
  16. // instead creates a JWT and sends that as the access token.
  17. // The audience is typically a URL that specifies the scope of the credentials.
  18. //
  19. // Note that this is not a standard OAuth flow, but rather an
  20. // optimization supported by a few Google services.
  21. // Unless you know otherwise, you should use JWTConfigFromJSON instead.
  22. func JWTAccessTokenSourceFromJSON(jsonKey []byte, audience string) (oauth2.TokenSource, error) {
  23. cfg, err := JWTConfigFromJSON(jsonKey)
  24. if err != nil {
  25. return nil, fmt.Errorf("google: could not parse JSON key: %v", err)
  26. }
  27. pk, err := internal.ParseKey(cfg.PrivateKey)
  28. if err != nil {
  29. return nil, fmt.Errorf("google: could not parse key: %v", err)
  30. }
  31. ts := &jwtAccessTokenSource{
  32. email: cfg.Email,
  33. audience: audience,
  34. pk: pk,
  35. pkID: cfg.PrivateKeyID,
  36. }
  37. tok, err := ts.Token()
  38. if err != nil {
  39. return nil, err
  40. }
  41. return oauth2.ReuseTokenSource(tok, ts), nil
  42. }
  43. type jwtAccessTokenSource struct {
  44. email, audience string
  45. pk *rsa.PrivateKey
  46. pkID string
  47. }
  48. func (ts *jwtAccessTokenSource) Token() (*oauth2.Token, error) {
  49. iat := time.Now()
  50. exp := iat.Add(time.Hour)
  51. cs := &jws.ClaimSet{
  52. Iss: ts.email,
  53. Sub: ts.email,
  54. Aud: ts.audience,
  55. Iat: iat.Unix(),
  56. Exp: exp.Unix(),
  57. }
  58. hdr := &jws.Header{
  59. Algorithm: "RS256",
  60. Typ: "JWT",
  61. KeyID: string(ts.pkID),
  62. }
  63. msg, err := jws.Encode(hdr, cs, ts.pk)
  64. if err != nil {
  65. return nil, fmt.Errorf("google: could not encode JWT: %v", err)
  66. }
  67. return &oauth2.Token{AccessToken: msg, TokenType: "Bearer", Expiry: exp}, nil
  68. }