1// Copyright 2020 Google LLC. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package idtoken 6 7import ( 8 "fmt" 9 "net/url" 10 "time" 11 12 "cloud.google.com/go/compute/metadata" 13 "golang.org/x/oauth2" 14 15 "google.golang.org/api/internal" 16) 17 18// computeTokenSource checks if this code is being run on GCE. If it is, it will 19// use the metadata service to build a TokenSource that fetches ID tokens. 20func computeTokenSource(audience string, ds *internal.DialSettings) (oauth2.TokenSource, error) { 21 if ds.CustomClaims != nil { 22 return nil, fmt.Errorf("idtoken: WithCustomClaims can't be used with the metadata service, please provide a service account if you would like to use this feature") 23 } 24 ts := computeIDTokenSource{ 25 audience: audience, 26 } 27 tok, err := ts.Token() 28 if err != nil { 29 return nil, err 30 } 31 return oauth2.ReuseTokenSource(tok, ts), nil 32} 33 34type computeIDTokenSource struct { 35 audience string 36} 37 38func (c computeIDTokenSource) Token() (*oauth2.Token, error) { 39 v := url.Values{} 40 v.Set("audience", c.audience) 41 v.Set("format", "full") 42 urlSuffix := "instance/service-accounts/default/identity?" + v.Encode() 43 res, err := metadata.Get(urlSuffix) 44 if err != nil { 45 return nil, err 46 } 47 if res == "" { 48 return nil, fmt.Errorf("idtoken: invalid response from metadata service") 49 } 50 return &oauth2.Token{ 51 AccessToken: res, 52 TokenType: "bearer", 53 // Compute tokens are valid for one hour, leave a little buffer 54 Expiry: time.Now().Add(55 * time.Minute), 55 }, nil 56} 57