jwt.go 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  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. }
  36. tok, err := ts.Token()
  37. if err != nil {
  38. return nil, err
  39. }
  40. return oauth2.ReuseTokenSource(tok, ts), nil
  41. }
  42. type jwtAccessTokenSource struct {
  43. email, audience string
  44. pk *rsa.PrivateKey
  45. }
  46. func (ts *jwtAccessTokenSource) Token() (*oauth2.Token, error) {
  47. iat := time.Now()
  48. exp := iat.Add(time.Hour)
  49. cs := &jws.ClaimSet{
  50. Iss: ts.email,
  51. Sub: ts.email,
  52. Aud: ts.audience,
  53. Iat: iat.Unix(),
  54. Exp: exp.Unix(),
  55. }
  56. hdr := &jws.Header{
  57. Algorithm: "RS256",
  58. Typ: "JWT",
  59. }
  60. msg, err := jws.Encode(hdr, cs, ts.pk)
  61. if err != nil {
  62. return nil, fmt.Errorf("google: could not encode JWT: %v", err)
  63. }
  64. return &oauth2.Token{AccessToken: msg, TokenType: "Bearer", Expiry: exp}, nil
  65. }