Jackjack
Jackjack

Reputation: 88

How to get a GCP identity-token programmatically with python

What is the python programmatic alternative to the gcloud command line gcloud auth print-identity-token?

I am trying to invoke Google Cloud Function by http trigger (only for auth users) and i need to pass the identity token in the Authentication header. I have method which works great when i run the code on GCP app engine. However, i struggle to find a way to get this identity token when i run the program on my own machine (where i can create the token with gcloud command line gcloud auth print-identity-token)

I found how to create access-token according to this answer but i didn't managed to understand how can i create identity-token.

Thank you in advance!

Upvotes: 4

Views: 6849

Answers (5)

Frederik Bode
Frederik Bode

Reputation: 2744

Code:

import requests
import google.auth

url = "https://oauth2.googleapis.com/token"
creds = google.auth.default()[0]
refresh_token = creds.refresh_token
client_secret = creds._client_secret
client_id = creds._client_id
params = {
    "grant_type": "refresh_token",
    "client_id": client_id,
    "client_secret": client_secret,
    "refresh_token": refresh_token,
}
params = "&".join([f"{key}={value}" for key, value in params.items()])
response = requests.post(url=url, params=params)
print(response.json()["id_token"])

So where does this magic come from? I ran:

gcloud config set core/log_http_redact_token false
gcloud auth print-identity-token --log-http
gcloud config set core/log_http_redact_token true

to see which http requests were being sent to google, and re-wrote calling the endpoint in python. It's no external library that does everything for you, but at least you don't require an entire gcloud to be installed.

Upvotes: 1

Akshay Shrivastava
Akshay Shrivastava

Reputation: 21

Struggled a bit to find the ideal solution for generating the token programatically, but found it in the official documentation itself eventually.

Sharing the python code snippet from the same

import urllib

import google.auth.transport.requests
import google.oauth2.id_token


def make_authorized_get_request(endpoint, audience):
    """
    make_authorized_get_request makes a GET request to the specified HTTP endpoint
    by authenticating with the ID token obtained from the google-auth client library
    using the specified audience value.
    """

    # Cloud Functions uses your function's URL as the `audience` value
    # audience = https://project-region-projectid.cloudfunctions.net/myFunction
    # For Cloud Functions, `endpoint` and `audience` should be equal

    req = urllib.request.Request(endpoint)

    auth_req = google.auth.transport.requests.Request()
    id_token = google.oauth2.id_token.fetch_id_token(auth_req, audience)

    req.add_header("Authorization", f"Bearer {id_token}")
    response = urllib.request.urlopen(req)

    return response.read()

Here's the link, hope it helps. Worked for me.

Upvotes: 1

Ryan
Ryan

Reputation: 815

You can run the shell command via subprocess.check_output from python and use the returned value as well.

This worked for me:

gcloud_itoken = subprocess.check_output(["gcloud","auth", "print-identity-token"])
gcloud_itoken_str = gcloud_itoken.decode().strip()
do_something(gcloud_itoken_str)

Upvotes: 0

peter
peter

Reputation: 31

If you have a service account you can impersonate this is one way to get an ID token in Python from a local/dev machine.

import google.auth
from google.auth.transport.requests import AuthorizedSession


def impersonated_id_token():
    credentials, project = google.auth.default(scopes=['https://www.googleapis.com/auth/cloud-platform'])
    authed_session = AuthorizedSession(credentials)
    sa_to_impersonate = "<SA_NAME>@<GCP_PROJECT>.iam.gserviceaccount.com"
    request_body = {"audience": "<SOME_URL>"}
    response = authed_session.post( f'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/{sa_to_impersonate}:generateIdToken',request_body)
    return response

if __name__ == "__main__":
    print(impersonated_id_token().json())

Upvotes: 0

guillaume blaquiere
guillaume blaquiere

Reputation: 75715

Great topic! And it's a long long way, and months of tests and discussion with Google.

TL;DR: you can't generate an identity token with your user credential, you need to have a service account (or to impersonate a service) to generate an identity token.

If you have a service account key file, I can share a piece of code to generate an identity token, but generating and having a service account key file is globally a bad practice.


I released an article on this and 2 merge requests to implement an evolution in the Java Google auth library (I'm more Java developer that python developer even if I also contribute to python OSS project) here and here. You can read them if you want to understand what is missing and how works the gcloud command today.

On the latest merge request, I understood that something is coming from google, internally, but up to now, I didn't see anything...

Upvotes: 6

Related Questions