Home | History | Annotate | Download | only in google
      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 
      5 package google
      6 
      7 import (
      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.
     26 func 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 
     48 type jwtAccessTokenSource struct {
     49 	email, audience string
     50 	pk              *rsa.PrivateKey
     51 	pkID            string
     52 }
     53 
     54 func (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