0

I have a cloud run application that I can call via terminal using:

curl -H \
"Authorization: Bearer $(gcloud auth print-identity-token)" \
https://url.run.app

I also have a cloud function and I want to have it call https://url.run.app and I need the bearer token as the one provided via the gcloud auth print-identify-token.

I want always the same token for the same account. For example, the following code provides me with the private and account that runs firebase. (my firebaseadmin account). Can I get a Bearer token that would work for cloud run

const { GoogleAuth } = require('google-auth-library');
const auth = new GoogleAuth();
await auth.getCredentials()

Is there a way to obtain the identity token?

Marc Anthony B
  • 3,635
  • 2
  • 4
  • 19
Michael
  • 1,759
  • 4
  • 19
  • 29
  • 1
    It is not clear what you are asking. What does this mean **The call is done through a third-party module so I cannot use the clients model from google-auth-library.**? – John Hanley Dec 21 '21 at 03:34
  • I need basically to get the Bearer Token that is given by this: gcloud auth print-identity-token – Michael Dec 21 '21 at 04:02
  • 1
    You are confusing an HTTP authentication scheme (Bearer) and an OIDC Identity Token. Google has published examples in a number of languages. Edit your question and specify exactly what you need to do. This answer might be one example of what you are looking for: https://stackoverflow.com/a/67122583/8016720 This link provides details on the basics: https://developers.google.com/identity/protocols/oauth2 – John Hanley Dec 21 '21 at 04:18
  • Thank you for the links but what I cannot understand is that the curl code as I wrote it works. So the identity token that is given passed into curl as a Bearer works. That tells me that it should be somehow retrievable. I updated my question with further examples of how far I managed to get. I can get my account's private key but do not know how to get the identity-token provided by the command line example that I gave. – Michael Dec 21 '21 at 04:30
  • 1
    Try this link: https://cloud.google.com/run/docs/authenticating/service-to-service#run-service-to-service-example-python – John Hanley Dec 21 '21 at 04:34
  • 1
    There is one item that you must do that the CLI does not need to do. That is specify the OIDC Identity Token Audience. That value is the URL of the service that you are calling. If you know how to code an HTTP GET Request, reproduce this while executing inside Cloud Functions: **curl "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=[AUDIENCE]" -H "Metadata-Flavor: Google"** – John Hanley Dec 21 '21 at 04:38
  • Thank you for the link to google authentication. The part that is a bit of a mystery is that in node the code returns a client object, ready for http get requests **const client = await auth.getIdTokenClient(targetAudience);** However, I want only the bearer token from the client. I do not know if the client has a method to return to me the bearer token. – Michael Dec 21 '21 at 04:52
  • 1
    The **getIdTokenClient** does not return a Bearer token in the way you are thinking. It returns an OIDC Identity Token which is what you want. **Bearer** is an HTTP Authentication scheme that supports many different token types. The documentation has examples for you to use now that I know you want Node.js: https://github.com/googleapis/google-auth-library-nodejs Example demo code: https://github.com/googleapis/google-auth-library-nodejs/blob/main/samples/idtokens-serverless.js – John Hanley Dec 21 '21 at 05:25
  • This indeed works for what I want to do. Thank you for your help! – Michael Dec 21 '21 at 21:42
  • Hi @JohnHanley, it seems that Michael did solved his problem by following you're guide. Could you please post it as answer so it would help the community. Thank you. – Marc Anthony B Dec 22 '21 at 08:10

2 Answers2

2

Summarizing John Hanley's Solution via comment:

There is one item that you must do that the CLI does not need to do. That is to specify the OIDC Identity Token Audience. That value is the URL of the service that you are calling. If you know how to code an HTTP GET Request, reproduce this while executing inside Cloud Functions:

curl "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=AUDIENCE" \
     -H "Metadata-Flavor: Google"

Where AUDIENCE is the URL of the service you are invoking (i.e. https://TARGET_HOSTNAME/).

The getIdTokenClient does not return a Bearer token in the way you are thinking. It returns an OIDC Identity Token which is what you want. Bearer is an HTTP Authentication scheme that supports many different token types. The documentation has examples for you to use.

Example demo code:

'use strict';

function main(
  url = 'https://service-1234-uc.a.run.app',
  targetAudience = null
) {
  if (!targetAudience) {
    // Use the target service's hostname as the target audience for requests.
    // (For example: https://my-cloud-run-service.run.app)
    const {URL} = require('url');
    targetAudience = new URL(url).origin;
  }
  // [START google_auth_idtoken_serverless]
  // [START cloudrun_service_to_service_auth]
  // [START run_service_to_service_auth]
  // [START functions_bearer_token]
  /**
   * TODO(developer): Uncomment these variables before running the sample.
   */
  // Example: https://my-cloud-run-service.run.app/books/delete/12345
  // const url = 'https://TARGET_HOSTNAME/TARGET_URL';

  // Example (Cloud Run): https://my-cloud-run-service.run.app/
  // Example (Cloud Functions): https://project-region-projectid.cloudfunctions.net/myFunction
  // const targetAudience = 'https://TARGET_HOSTNAME/';
  const {GoogleAuth} = require('google-auth-library');
  const auth = new GoogleAuth();

  async function request() {
    console.info(`request ${url} with target audience ${targetAudience}`);
    const client = await auth.getIdTokenClient(targetAudience);
    const res = await client.request({url});
    console.info(res.data);
  }

  request().catch(err => {
    console.error(err.message);
    process.exitCode = 1;
  });
  // [END functions_bearer_token]
  // [END run_service_to_service_auth]
  // [END cloudrun_service_to_service_auth]
  // [END google_auth_idtoken_serverless]
}

const args = process.argv.slice(2);
main(...args);
Donnald Cucharo
  • 3,866
  • 1
  • 10
  • 17
Marc Anthony B
  • 3,635
  • 2
  • 4
  • 19
0

The following worked on our end - tested and validated the token with Axios too.

const {GoogleAuth} = require('google-auth-library');
const targetAudience = 'https://my-cloud-run.nn.a.run.app/'
const auth = new GoogleAuth();
const client = await auth.getIdTokenClient(targetAudience)
const idToken = await client.idTokenProvider.fetchIdToken(targetAudience);
cypher15
  • 104
  • 7