How can I retrieve an id_token to access a Google Cloud Function?
I'm trying to generate a id_token to make authenticated calls to Google Cloud Functions using this following code, that I got from here:
# IAP audience is the ClientID of IAP-App-Engine-app in
# the API->credentials page
# Cloud Function and Cloud Run need the base URL of the service
audience = 'my_cloud_function_url'
# #1 Get the default credential to generate the access token
credentials, project_id = google.auth.default()
# #2 To use the current service account email
service_account_email = credentials.service_account_email
# Don't work with user account, so define manually the email
# service_account_email = 'MY SERVICE ACCOUNT EMAIL'
# #3 prepare the call the the service account credentials API
sa_credentials_url = f'https://iamcredentials.googleapis.com/' \
f'v1/projects/-/serviceAccounts/' \
f'{service_account_email}:generateIdToken'
headers = {'Content-Type': 'application/json'}
# Create an AuthorizedSession that includes
# automatically the access_token based on your credentials
authed_session = AuthorizedSession(credentials)
# Define the audience in the request body
# add the parameter "'includeEmail':true" for IAP access
body = json.dumps({'audience': audience})
# Make the call
token_response = authed_session.request('POST',sa_credentials_url,
data=body, headers=headers)
jwt = token_response.json()
id_token = jwt['token']
I'm not running it into a Google Cloud environment, so I set my GOOGLE_APPLICATION_CREDENTIALS to a json file from a service account I generated in the console. I asked my network manager to authorize the service account within the ['https://www.googleapis.com/auth/cloud-platform'] scope.
When I run the script, I get the following error:
{'error': {'code': 403, 'message': 'The caller does not have permission', 'status': 'PERMISSION_DENIED'}}
I imagine that this error has something to do with not having some intern access with this service account, but I'm not sure, can anybody help me with this?
Edit:
As stated by @guillaume blaquiere on the comments, you can get the id_token without calling the Service Account Credential API, And I could obtain the id_token, but was unable to call my service account with that id_token
import google.oauth2.id_token
import google.auth.transport.requests
request = google.auth.transport.requests.Request()
audience = 'my_cloud_function_url'
id_token = google.oauth2.id_token.fetch_id_token(request, audience)
headers = {'Authorization': f'bearer {id_token}'}
service_response = requests.get(audience, headers=headers)
Does anyone knows why thes id_token is invalid?
The 403 error The caller does not have permission
means that the running service account of your Cloud Function doesn't have the required role to invoke the function. Could you go to IAM and check if your service account has Cloud Functions Invoker role? If the service account doesn't have the permission, then please follow this step:
- Check the role of your Service Account in IAM, look for Role column and verify if it doesn't have the role mentioned above.
- To add permission, hover to your Service Account then Click edit in the right side column named
Inheritance
. - Select the role Cloud Functions > Cloud Functions Invoker from the Select a role drop-down menu.
- Click Save.
You don't need to call the Service Account Credential API, you can use the fetch_id_token
method (but you have to know which it exists! It's not very well known and documented!)
import google.oauth2.id_token
import google.auth.transport.requests
request = google.auth.transport.requests.Request()
audience = 'my_cloud_function_url'
id_token = google.oauth2.id_token.fetch_id_token(request, audience)
The library use the default credential that you set in the GOOGLE_APPLICATION_CREDENTIALS
env vars. So, it's convenient to get an ID token with this python lib!