// newClient creates http.Client with a jwt service account when // jsonFile flag is specified, otherwise by obtaining the GCE service // account's access token. func newClient(jsonFile string) (*http.Client, error) { if jsonFile != "" { jsonKey, err := ioutil.ReadFile(jsonFile) if err != nil { return nil, err } conf, err := google.JWTConfigFromJSON(jsonKey, pubsub.ScopePubSub) if err != nil { return nil, err } return conf.Client(oauth2.NoContext), nil } if metadata.OnGCE() { c := &http.Client{ Transport: &oauth2.Transport{ Source: google.ComputeTokenSource(""), }, } if *projID == "" { projectID, err := metadata.ProjectID() if err != nil { return nil, fmt.Errorf("ProjectID failed, %v", err) } *projID = projectID } return c, nil } return nil, errors.New("Could not create an authenticated client.") }
func (cs computeSource) Token() (*oauth2.Token, error) { if !metadata.OnGCE() { return nil, errors.New("oauth2/google: can't get a token from the metadata service; not running on GCE") } acct := cs.account if acct == "" { acct = "default" } tokenJSON, err := metadata.Get("instance/service-accounts/" + acct + "/token") if err != nil { return nil, err } var res struct { AccessToken string `json:"access_token"` ExpiresInSec int `json:"expires_in"` TokenType string `json:"token_type"` } err = json.NewDecoder(strings.NewReader(tokenJSON)).Decode(&res) if err != nil { return nil, fmt.Errorf("oauth2/google: invalid token JSON from metadata: %v", err) } if res.ExpiresInSec == 0 || res.AccessToken == "" { return nil, fmt.Errorf("oauth2/google: incomplete token received from metadata") } return &oauth2.Token{ AccessToken: res.AccessToken, TokenType: res.TokenType, Expiry: time.Now().Add(time.Duration(res.ExpiresInSec) * time.Second), }, nil }
// DefaultTokenSource is a token source that uses // "Application Default Credentials". // // It looks for credentials in the following places, // preferring the first location found: // // 1. A JSON file whose path is specified by the // GOOGLE_APPLICATION_CREDENTIALS environment variable. // 2. A JSON file in a location known to the gcloud command-line tool. // On Windows, this is %APPDATA%/gcloud/application_default_credentials.json. // On other systems, $HOME/.config/gcloud/application_default_credentials.json. // 3. On Google App Engine it uses the appengine.AccessToken function. // 4. On Google Compute Engine, it fetches credentials from the metadata server. // (In this final case any provided scopes are ignored.) // // For more details, see: // https://developers.google.com/accounts/application-default-credentials // func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSource, error) { // First, try the environment variable. const envVar = "GOOGLE_APPLICATION_CREDENTIALS" if filename := os.Getenv(envVar); filename != "" { ts, err := tokenSourceFromFile(ctx, filename, scope) if err != nil { return nil, fmt.Errorf("google: error getting credentials using %v environment variable: %v", envVar, err) } return ts, nil } // Second, try a well-known file. filename := wellKnownFile() _, err := os.Stat(filename) if err == nil { ts, err2 := tokenSourceFromFile(ctx, filename, scope) if err2 == nil { return ts, nil } err = err2 } else if os.IsNotExist(err) { err = nil // ignore this error } if err != nil { return nil, fmt.Errorf("google: error getting credentials using well-known file (%v): %v", filename, err) } // Third, if we're on Google App Engine use those credentials. if appengineTokenFunc != nil { return AppEngineTokenSource(ctx, scope...), nil } // Fourth, if we're on Google Compute Engine use the metadata server. if metadata.OnGCE() { return ComputeTokenSource(""), nil } // None are found; return helpful error. const url = "https://developers.google.com/accounts/application-default-credentials" return nil, fmt.Errorf("google: could not find default credentials. See %v for more information.", url) }