How do I get access token inside Node.JS Google Cloud function?
Asked Answered
P

4

8

I have a cloud function in Node.JS on Google Cloud, I need to make GET request to Google and it requires an auth token. Using curl you can generate one using $(gcloud auth application-default print-access-token). But this doesn't work in Cloud instance so how I can generate one?

Some of the function:

exports.postTestResultsToSlack = functions.testLab
  .testMatrix()
  .onComplete(async testMatrix => {

    if (testMatrix.clientInfo.details['testType'] != 'regression') {
      // Not regression tests
      return null;
    }

    const { testMatrixId, outcomeSummary, resultStorage } = testMatrix;

    const projectID = "project-feat1"
    const executionID = resultStorage.toolResultsExecutionId
    const historyID = resultStorage.toolResultsHistoryId

    const historyRequest = await axios.get(`https://toolresults.googleapis.com/toolresults/v1beta3/projects/${projectID}/histories/${historyID}/executions/${executionID}/environments`, {
      headers: {
        'Authorization': `Bearer $(gcloud auth application-default print-access-token)`,
        'X-Goog-User-Project': projectID
      }
    });
Persistence answered 4/11, 2021 at 17:39 Comment(5)
Are you facing any error while doing this? If so, could you provide your error here?Senegambia
Error: Request failed with status code 401Persistence
Check out the document on generating tokens programmatically using Nodejs. This document speaks about the 401 error and its solution. Also I have found some threads similar to your issue, check out these once: Thread1, Thread2, Thread3Senegambia
The first link is broken.Persistence
Try this one: LinkSenegambia
P
8

After countless hours spent, I stumbled across the answer scrolling through auto complete suggestions. Google has documentation about authentication but none mention this what you need for Cloud Functions to make API requests:

const {GoogleAuth} = require('google-auth-library');

const auth = new GoogleAuth();
const token = await auth.getAccessToken()

const historyRequest = await axios.get(
`https://toolresults.googleapis.com/toolresults/v1beta3/projects/${projectID}/histories/${historyID}/executions/${executionID}/environments`, 
      {
        headers: {
          'Authorization': `Bearer ${token}`,
          'X-Goog-User-Project': projectID
        }
    });
Persistence answered 9/11, 2021 at 9:17 Comment(2)
Note that you need to define the GOOGLE_APPLICATION_CREDENTIALS environment variable for this to work. Also, I had to give an explicit scopes string to the constructor const auth = new GoogleAuth({scopes: 'https://www.googleapis.com/auth/cloud-platform'}); otherwise you get the following on .getAccessToken(): 400 Bad Request { error: 'invalid_scope', error_description: 'Invalid OAuth scope or ID token audience provided.' }Salba
see cloud.google.com/storage/docs/reference/… or github.com/googleapis/google-auth-library-nodejs for moreSalba
G
0

Here was my final working code for google auth. Similar to the above, but with credentials as a base 64 environment variable.

import {GoogleAuth} from 'google-auth-library';

function getGoogleCredentials() {
  const base64Data = process.env.BASE_64_CREDENTIALS!
  // Convert the base64 string back to a Buffer
  const bufferData = Buffer.from(base64Data, 'base64');

  // Convert the Buffer back to a JSON string
  const jsonData = bufferData.toString('utf-8');

  // Parse the JSON string to get the JavaScript object
  const jsonObject = JSON.parse(jsonData);
  return {
    private_key: jsonObject.private_key,
    client_email: jsonObject.client_email
  }
}

const auth = new GoogleAuth({
  scopes: "https://www.googleapis.com/auth/cloud-platform",
  credentials: getGoogleCredentials()
});
const token = await auth.getAccessToken()

I cannot for the life of me understand how google expects one to do this differently using any kind of automated deployment software.

Generation answered 4/11, 2023 at 23:25 Comment(0)
V
0

I had the same problem but calling Google Translate API, to create a token you need to add scopes, and if you are using a service account, grant the service Usage Consumer role.

const {GoogleAuth} = require('google-auth-library');

const auth = new GoogleAuth({
  scopes: 'https://www.googleapis.com/auth/cloud-platform',
});
const token = await auth.getAccessToken()

const body = {sourceLanguageCode: 'en',targetLanguageCode: 'ru',contents: ['Dr. Watson, come here!', 'Bring me some coffee!'],};

const request = await axios.post('https://translation.googleapis.com/v3/projects/[project-id]:translateText', body, {
    headers: { Authorization: `Bearer ${token}`, 'x-goog-user-project': '[project-id]' },
  })
Valadez answered 14/11, 2023 at 0:30 Comment(0)
P
0

I followed all of my above answers didn't work. After I created cloud function from cmd following tutorial https://cloud.google.com/functions/docs/create-deploy-http-nodejs#:~:text=To%20deploy%20your%20function%2C%20run,See%20more%20code%20actions.&text=Replace%20REGION%20with%20the%20name,example%2C%20us-west1%20).

gcloud functions deploy watermark-image-function ^
--gen2 ^
--runtime=nodejs20 ^
--region=europe-west3 ^
--source=. ^
--entry-point=waterMarkImage ^
--trigger-http ^
--allow-unauthenticated

I have to run: "gcloud auth print-identity-token" on my signed in cloudshell But I want deployed Nodejs to get OIDC token in order to run cloud function. Firstly, I created a Service Account. Then make sure to Grant Access service account principal: ServiceAccountEmail, Role: Cloud Run Invoker https://i.sstatic.net/9n5lJhKN.png

Also Add key with selecting JSON and download it.

const { GoogleAuth } = require("google-auth-library");
async function getAccessToken(){
   const keyFile="C:\\visioniert-423714-f6ae290acaed.json"; //service account key file
   const audience = "https://europe-west3-visioniert-423714.cloudfunctions.net/watermark-image-function"; // Go to your Cloud function and find "Trigger" tab to get your cloud function URL 
   const auth = new GoogleAuth({
      keyFile: keyFile,
   });

   const client = await auth.getIdTokenClient(audience);
   const tokenResponse = await client.getRequestHeaders();
   console.log( tokenResponse["Authorization"].split(" ")[1]);
}

[1]: https://cloud.google.com/functions/docs/create-deploy-http-nodejs#:~:text=To%20deploy%20your%20function%2C%20run,See%20more%20code%20actions.&text=Replace%20REGION%20with%20the%20name,example%2C%20us%2Dwest1%20). [2]: https://i.sstatic.net/9n5lJhKN.png

Pachisi answered 2/6, 2024 at 12:44 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.