| // 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 serive, 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 | |
| } |