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