Search code examples
gogoogle-cloud-platformgcloud

Get access token for a google cloud service account in Golang?


I'm using a service account on google cloud. For some reason, I want to get the access token programmatically in golang. I can do gcloud auth application-default print-access-token on the command line.

There is a library by google that seems to allow me to get the token. Here is how I try to use it:

    credentials, err := auth.FindDefaultCredentials(ctx)
    if err == nil {
        glog.Infof("found default credentials. %v", credentials)
        token, err2 := credentials.TokenSource.Token()
        fmt.Printf("token: %v, err: %v", token, err2)
        if err2 != nil {
            return nil, err2
        }

However, I get an error saying token: <nil>, err: oauth2: cannot fetch token: 400 Bad Request.

I already have GOOGLE_APPLICATION_CREDENTIALS env variable defined and pointing to the json file.


Solution

  • Running your code as-is, returns an err:

    Invalid OAuth scope or ID token audience provided
    

    I added the catch-all Cloud Platform writable scope from Google's OAuth scopes:

    https://www.googleapis.com/auth/cloud-platform
    

    Doing so, appears to work. See below:

    package main
    
    import (
        "context"
        "log"
    
        "golang.org/x/oauth2"
        auth "golang.org/x/oauth2/google"
    )
    
    func main() {
        var token *oauth2.Token
        ctx := context.Background()
        scopes := []string{
            "https://www.googleapis.com/auth/cloud-platform",
        }
        credentials, err := auth.FindDefaultCredentials(ctx, scopes...)
        if err == nil {
            log.Printf("found default credentials. %v", credentials)
            token, err = credentials.TokenSource.Token()
            log.Printf("token: %v, err: %v", token, err)
            if err != nil {
                log.Print(err)
            }
        }
    }
    

    I had some challenges using this library recently (to access Cloud Run services which require a JWT audience). On a friend's recommendation, I used google.golang.org/api/idtoken instead. The API is very similar.