// Copyright 2020 Google LLC. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package idtoken import ( "fmt" "net/url" "time" "cloud.google.com/go/compute/metadata" "golang.org/x/oauth2" "google.golang.org/api/internal" ) // computeTokenSource checks if this code is being run on GCE. If it is, it will // use the metadata service to build a TokenSource that fetches ID tokens. func computeTokenSource(audience string, ds *internal.DialSettings) (oauth2.TokenSource, error) { if ds.CustomClaims != nil { 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") } ts := computeIDTokenSource{ audience: audience, } tok, err := ts.Token() if err != nil { return nil, err } return oauth2.ReuseTokenSource(tok, ts), nil } type computeIDTokenSource struct { audience string } func (c computeIDTokenSource) Token() (*oauth2.Token, error) { v := url.Values{} v.Set("audience", c.audience) v.Set("format", "full") urlSuffix := "instance/service-accounts/default/identity?" + v.Encode() res, err := metadata.Get(urlSuffix) if err != nil { return nil, err } if res == "" { return nil, fmt.Errorf("idtoken: invalid response from metadata service") } return &oauth2.Token{ AccessToken: res, TokenType: "bearer", // Compute tokens are valid for one hour, leave a little buffer Expiry: time.Now().Add(55 * time.Minute), }, nil }