Search code examples
gooauth-2.0google-cloud-functions

Google access token does not work within cloud functions


I'm using this example provided under cloud functions to make a GET request to another GCP API:

import (
        "context"
        "fmt"
        "io"

        "google.golang.org/api/idtoken"
)

func makeGetRequest(w io.Writer, targetURL string) error {
        ctx := context.Background()

        client, err := idtoken.NewClient(ctx, targetURL)
        if err != nil {
                return fmt.Errorf("idtoken.NewClient: %v", err)
        }

        resp, err := client.Get(targetURL)
        if err != nil {
                return fmt.Errorf("client.Get: %v", err)
        }
        defer resp.Body.Close()
        if _, err := io.Copy(w, resp.Body); err != nil {
                return fmt.Errorf("io.Copy: %v", err)
        }
        return nil
}

but when I log the request sent I don't see any authorization header and I get the following error:

"Request
  had invalid authentication credentials. Expected OAuth 2 access token, login cookie
  or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.\"

I have given serviceAccountTokenCreator and the target GCP API admin permissions to the service account that's used to create the cloud function.

Am I misunderstanding what the documentation is saying? It seems like the authorization header should be automatically added.


Solution

  • It might be easier for you to not build the request from scratch and use Client Libraries instead. It provides idiomatic, generated or hand-written code in each language, making the Cloud API simple and intuitive to use. It also handles authentication for you.

    From what you're following, the client automatically adds an "Authorization" header so that shouldn't be the problem. You're also trying to follow an example that generates an Identity Token, because calling a Cloud Function endpoint that has authentication requires an Identity token. This is different on your use case, because calling GCP APIs require an OAuth 2 access token. This link explains the difference between the two.

    There are ways to generate an access token programmatically such as getting them from the metadata server as I did in my other answer (it's in Python but you can also do it in Golang). However, I suggest learning more on how Client Libraries work and test it for yourself. There are many examples shown on GitHub to get you started.