I want to authenticate Gsuite users in order for them to be able to create groups from my company's application, I have to do so using CURL, what URL should I send a post request to?
For example, if I want to login a user to Google plus, I would hit this url
CURLOPT_URL => "https://www.googleapis.com/plus/v1/people/me?access_token=" . $access_token,
What url is for Gsuite?
If your goal is to retrive the information about a user in G Suite:
CURLOPT_URL => "https://www.googleapis.com/admin/directory/v1/users/john#example.com?access_token=" . $access_token;
Note: Please consult the Directory API on how delegation is performed. This is required. Normal Access Tokens will not work without Domain-wide Delegation enabled.
Your credentials (Access Token) will need the correct scopes:
https://www.googleapis.com/auth/admin.directory.group
https://www.googleapis.com/auth/admin.directory.user
Your credentials will need the correct delegation.
Python example:
SCOPES = [
"https://www.googleapis.com/auth/admin.directory.group",
"https://www.googleapis.com/auth/admin.directory.user"
]
key_file = 'google-directory-api-service-account.json'
SERVICE_ACCOUNT_EMAIL = 'directory#development-123456.iam.gserviceaccount.com'
ADMIN_EMAIL = 'gsuite-admin#example.com'
credentials = service_account.Credentials.from_service_account_file(
key_file,
scopes = SCOPES)
credentials = credentials.with_subject(ADMIN_EMAIL)
Domain-wide Delegation
See the bottom of this answer for common errors that I have seen when setting up G Suite access.
If your goal is to retrieve information stored within a Google OAuth 2.0 Token:
These urls expects a Google OAuth 2.0 Access Token. The alt=json specifies returning JSON.
Examples that you can test in a command prompt:
curl -k "https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=ACCESS_TOKEN"
curl -k "https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=ACCESS_TOKEN"
There is also the v3 endpoint for :
curl -k "https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=ACCESS_TOKEN"
Common problems when setting up API access to G Suite:
Access Not Configured. Admin Directory API has not been used in project 123456789012 before or it is disabled.
Go to the Google Cloud Console. Enable the API for Admin SDK.
Not Authorized to access this resource/api.
You have not setup Domain-wide delegation correctly.
Client is unauthorized to retrieve access tokens using this method
You tried to setup Domain-wide delegation on an existing service account. You need to create a new service account that does not have any IAM Roles assigned.
Related
I am a novice developer who wants to learn how to use artificial intelligence.
So I created model and it responds correctly according to the inputs.
So I want to test using postman a call to the API to verify that everything works and I have an error in my call:
"message": "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.",
"status": "UNAUTHENTICATED"
I don't know how to authenticate myself to retrieve the access token. Could you help me find a solution please?
You have 2 solutions:
As John commented,
Install the gcloud SDK on your computer.
Authenticate yourselves with the command gcloud auth login or gcloud init (proposed at the end of the installation)
Generate an access token gcloud auth print-access-token and copy it
Tips: you can skip the 2 first steps if you use Cloud Shell
Add the access token to the header to your Postman request like this:
Key is "Authrorization"
Value is "Bearer "
The access token is valid 1H, then you have to generate a new one.
(Not recommended) Make your model public (i.e. unauthenticated) like this (only in command line, it doesn't work on the GUI)
gcloud ai-platform models add-iam-policy-binding --member="allUsers" \
--role="roles/ml.modelOwner" <Model Name>
replace Model Name by your deployed model. However, it's only for test purpose. You have any filter and anyone can use it and you will pay for the processing incurs.
We need to use an API to verify if a certain user exists as managed account (it means, that belongs to our Google Domain organization).
GSuite adminSDK performs that operation, however, it requires OAuth2 authentication, authorized by an authenticated user - https://developers.google.com/admin-sdk/reports/v1/guides/authorizing .
My question is, if there any way to use that API with service account, or any other methos to retrieve this information with service account, since it would be used in a Server-2-Server scenario.
Thanks,
Vasco
As you may know, Service Accounts don't belong to an individual end user, but to an application. An administrator of a G Suite domain, though, can authorize the Service Account to access user data, that is, to impersonate users in the domain. This is called domain-wide delegation.
To achieve this, go to the Admin console and follow the steps specified here.
Reference:
Delegating domain-wide authority to the service account
Reports API > Perform G Suite Domain-Wide Delegation of Authority
Since this is completely not obvious - the docs "hint" at this, but don't spell it out and I had trouble finding any specific examples that worked. They all kept returning this error:
Google.GoogleApiException: 'Google.Apis.Requests.RequestError
Not Authorized to access this resource/api [403]
Errors [
Message[Not Authorized to access this resource/api] Location[ - ] Reason[forbidden] Domain[global]
]
The basic issue that the service account MUST impersonate another user. It's mentioned in this link at the bottom, highlighted in blue:
https://developers.google.com/admin-sdk/directory/v1/guides/delegation
Only users with access to the Admin APIs can access the Admin SDK Directory API, therefore your service account needs to impersonate one of those users to access the Admin SDK Directory API. Additionally, the user must have logged in at least once and accepted the Google Workspace Terms of Service.
But it just wasn't clicking as to how I was supposed to do that - was this some setting hiding in one of the admin consoles? No - you pass this as part of your initial connection.
So just to put the instructions in one place and hopefully save someone else the same headache, these were the steps:
Created a project via https://console.developers.google.com
Searched for then enabled the Admin SDK API
Created a Service Account
Show domain-wide delegation / Enable G Suite Domain-wide Delegation
At this point I had a service account name, unique ID, Email, and Client ID
It generated a key file (json) that I downloaded.
Go to: https://admin.google.com
Security > API Controls.
Manage Domain Wide Delegation
Added entry using client ID from above, applied these two scopes - you can apply other scopes as needed.
https://www.googleapis.com/auth/admin.directory.user.readonly
https://www.googleapis.com/auth/admin.directory.group.member.readonly
Then I created a .NET Core console app and installed these NuGet packages:
Google.Apis
Google.Apis.Auth
Google.Apis.Admin.Directory.directory_v1
Here's an ugly proof of concept with everything working:
using System;
using System.IO;
using System.Net;
using Google.Apis.Admin.Directory.directory_v1;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
namespace GoogleDirectoryTest
{
class Program
{
static void Main(string[] args)
{
var dirService = GetDirectoryService(#"C:\tmp\google-cred-sample-12345abdef.json", "user-with-admin-permission-here#mydomainhere.com", "My App Name");
var list = dirService.Users.List();
list.Domain = "mydomainhere.com";
var users = list.Execute();
foreach (var user in users.UsersValue)
{
Console.WriteLine($"{user.Name.FullName}");
}
Console.ReadKey();
}
static DirectoryService GetDirectoryService(string keyfilepath, string impersonateAccount, string appName)
{
using (var stream = new FileStream(keyfilepath, FileMode.Open, FileAccess.Read))
{
var credentials = GoogleCredential.FromStream(stream).CreateWithUser(impersonateAccount);
if (credentials.IsCreateScopedRequired)
credentials = credentials.CreateScoped(new[] { DirectoryService.Scope.AdminDirectoryUserReadonly });
var service = new DirectoryService(new BaseClientService.Initializer()
{
HttpClientInitializer = credentials,
ApplicationName = appName,
});
return service;
}
}
Hopefully this saves someone else some headaches.
A service account is a special kind of account used by an application, rather than a person.
You can use a service account to access data or perform actions by the robot account itself, or to access data on behalf of Google Workspace or Cloud Identity users.
Prerequisites:
A Google Cloud Platform project
With the Admin SDK API enabled service account with domain-wide delegation.
A Google Workspace domain.
With account in that domain with administrator privileges.
Visual Studio 2013 or later
Step 1: Set up the Google Cloud Platform project
Create Google Cloud project
A Google Cloud project is required to use Google Workspace APIs and build Google Workspace add-ons or apps.
If you don't already have a Google Cloud project, refer to: How to create a Google Cloud project
Enable Google Workspace APIs
Before using Google APIs, you need to enable them in a Google Cloud project.
To Enable Google Workspace APIs refer to: How to Enable Google Workspace APIs
For this example you are enabling the the Admin SDK Directory API
with the data scope /auth/admin.directory.user.readonly.
Create Service Account with domain-wide delegation
To create service account refer to: How to create service account?
In the Domain wide delegation pane, select Manage Domain Wide Delegation.
Download Service Account private key (p12 format)
Download p12 file contains the private key for your Service Account.
Step 2: Set up the Google Workspace
Enable API access in the Google Workspace domain with
To enable API access in Google Workspace domain, refer to: how to enable API access
Delegating domain-wide authority to the service account
To call APIs on behalf of users in a Google Workspace organization, your service account needs to be granted domain-wide delegation of authority in the Google Workspace Admin console by a super administrator account
To delegating domain-wide authority in Google Workspace domain, refer to: How to Delegating domain-wide authority to the service account
Step 3: Prepare Visual Stodio project -
Create a new Visual C# Console Application (.NET Framework) project in Visual Studio.
Open the NuGet Package Manager Console, select the package source nuget.org, and run the following commands:
Install-Package Google.Apis.Auth
Install-Package Google.Apis.Admin.Directory.directory_v1
Step 4: Add code
Full example at GitHub
List top 10 users alias from Google Workspace Domain
/// <summary>
/// Example how to list all users from google workspace domain, using a service account (user impersonation).
/// </summary>
internal class Program {
static void Main(string[] args) {
// Scope for only retrieving users or user aliases.
string[] _scopes = {
"https://www.googleapis.com/auth/admin.directory.user.readonly"
};
var _paramters = new SACInitializeParameters(
// The service account ID (typically an e-mail address like: *#*iam.gserviceaccount.com)
serviceAccountId: "[Service Account ID]",
// The full path; name of a certificate file
x509CertificateFilePath: "[X509 Certificate File]",
// The email address of the user you trying to impersonate
impersonateEmail: "[User Email]",
// The scopes which indicate API access your application is requesting
scopes: _scopes);
using (var directoryService = DirectoryServiceFactory.CreateDirectoryService(_paramters)) {
// Retrieves a paginated list of either deleted users or all users in a domain.
var request = directoryService.Users.List();
// The unique ID for the customer's Google Workspace account
// the `my_customer` alias represent current identety account's
request.Customer = "my_customer";
request.MaxResults = 10;
var response = request.Execute();
foreach (var user in response.UsersValue) {
System.Console.WriteLine($"{user.Name.FullName}, {user.PrimaryEmail}, {user.Id}");
}
}
}
}
In order to authenticate with Cloud Endpoints for OpenAPI, I have to construct a Python requests session using google-auth as follows:
from google.auth.transport.requests import AuthorizedSession
creds = google.auth.jwt.Credentials.from_service_account_file(
creds_path, audience=my_audience)
session = AuthorizedSession(creds)
But when I want to authenticate to a Cloud Function, I have to do it a little different:
creds = google.oauth2.service_account.IDTokenCredentials.from_service_account_file(creds_path, target_audience=function_url)
session = AuthorizedSession(creds)
And all that is when I use a service account file, such as when running from my local machine, or on GKE. But when it's used on App Engine, there's another variant:
Calling Cloud Endpoints -
boostrap_creds, _ = google.auth.default()
creds = google.auth.jwt.Credentials.from_signing_credentials(boostrap_creds, my_audience)
session = AuthorizedSession(creds)
Calling Cloud Function --
IAM_SCOPE = 'https://www.googleapis.com/auth/iam'
OAUTH_TOKEN_URI = 'https://www.googleapis.com/oauth2/v4/token'
bootstrap_credentials, _ = google.auth.default(scopes=[IAM_SCOPE])
signer_email = bootstrap_credentials.service_account_email
signer = bootstrap_credentials.signer
creds = google.oauth2.service_account.IDTokenCredentials(
signer, signer_email, token_uri=OAUTH_TOKEN_URI, target_audience=function_url)
session = AuthorizedSession(creds)
Why is there a difference, and what does it mean?
In the Cloud Endpoints when you use: google.auth.jwt.Credentials to authenticate a user, a client application sending JSON Web Token (JWT) in the authorization header of the HTTP request to your backend API. There are two components to the token, a public and private string. The private string is used when signing the request, and never sent across the wire. The Extensible Service Proxy (ESP) validates the token for your API, so you don't add any code in your API to process the authentication. Those Access tokens, are not intended to carry information about the user. They simply allow access to certain defined server resources. Endpoints uses plain OAuth 2.
In the Cloud Function when you use: google.oauth2.service_account.IDTokenCredentials to autenticate uses oAuth2 ID token. ID Token is a token granted by the OpenID Provider that contains information about End-User, in this situation about service account. This information tells client application that the user is authenticated, and can also give information like their username.
You can pass an ID Token around different components of your client, and these components can use the ID Token to confirm that the user is authenticated and also to retrieve information about them. Functions uses more advanced OpenID Connect.
If you want to know more about OAuth:
Differences between OAuth 1 and 2.
OpenID connect
I was using Amazon Cognito user pool for login. When I access my web application, I get a redirect to
https://<domain>.auth.<region>.amazoncognito.com/login?response_type=code&client_id=<client id>&redirect_uri=<callback> .
Once logged in with the username/password of a user from the pool, I will be redirected to the callback URL with the code as a query parameter. I can use this to get tokens. How do I integrate this in postman so that I can use the token for my upcoming request?
I have an example of doing this...
The callback URL as defined in the Cognito User Pool console under App Integration / App client settings.
The URL for the login endpoint of your domain. This will be under Cognito User Pool / App Integration / Domain Name
Client ID is found under Cognito User Pool / General Settings / App clients
List the scopes you want to include in the Access Token. These must be enabled under Cognito User Pool / App Integration / App client settings. These can be either standard or custom scopes. Custom scopes are defined under App Integration / Resource servers and must include the resource server ID (e.g. https://myresource.com/myscope)
Click Request Token
You may now log in to your Cognito User Pool and receive an Access Token!
The problem is that once you have the Access Token it isn't usable within Postman because Cognito expects it to be bare and Postman automatically prepends 'Bearer' to the token:
The token can be used in cURL though:
curl -i -H "Authorization: dyJraWQiOiI1YVcwTUlqN1hBaHg4Yzh4Q3JNT2RsQjhZWjlCR3NQOE9BbkFlVFJtUklRPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiI3YmEwZmMzOC01ZDcwkYS05MTI5ZTBmYTUzNTEiLCJ0b2tlbl91c2UiOiJhY2Nlc3MiLCJzY29wZSI6Imh0dHBzOlwvXC9hcGkubXk5MC5jb21cL3BvbGljZURlcGFydG1lbnRzLnJlYWQiLCJhdXRoX3RpbWUiOjE1NDA1OTIzMTYsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC51cy1lYXN0LTEuYW1hem9uYXdzLmNvbVwvdXMtZWFzdC0xX2xIbGo4NXpRYSIsImV4cCI6MTU0MDU5NTkxNiwiaWF0IjoxNTQwNTkyMzE2LCJ2ZXJzaW9uIjoyLCJqdGkiOiJhN2JiOWU2MC1kNmY1LTQ3ODYtODMwYi0xODdkZDZmYTZlODAiLCJjbGllbnRfaWQiOiI2MzhlYmZ1dTdiZDRkMXVkYnRzY2pxcnJncyIsInVzZXJuYW1lIjoicm9qbyJ9.O_GAxfFX3IQfLUu5Hxr05Wrk_2QDwNSL8tvDdEU0Dzs9d1XhQPafT6ney6yiGnKPOwsO8HhWdbT1QdDmByjuwQAURf1Da4Au7c-yhfgJcqWuHWZ4mledTSP8ukXqihMb4PoaDdU4JXyOdMLa50dBXVMgJNyXTpIulWOxFhiTW6DeQbnxNDk94cGNz_CTKCEqKStiloFZfLR7ndSrWqdOQ_SU__YV0RyKXZyK5yguv3nkUcI6cuKpbPVIZ5DNdpufbrtOLuZcC6HePBKrbTKjSZCt5-swy3YrwnY4ApTX7QUFzof6FylWaLA_KVP3Zv6ksSJ_IjBMFH1NRVHh4lbsOA" \
https://xxxxx.execute-api.us-east-1.amazonaws.com/v1/myresource/1234
by yl.
Thanks to Robert Jordan for his above postman OAuth2.0 configuration post.
I'll try to cover here the entire Cognito user pool definition part to make it easier.
Ok,
Open the Cognito console and follow the bellow stages:
1) create new user pool
name: Test1
left panel menu->Attributes
Select the following radio buttons:
o Email address or phone number - Users can use an email address or phone number as
their "username" to sign up and sign in.
o Allow email addresses
And checkboxes:
[v] email
[v] name
Screenshot:
Press the [Create Pool] button.
(if not available yet to the wizard - press [Review Details] option on the left panel menu)
2) left panel menu->App Clients
press: [add app client]
App client name: me1
clear all checkboxes but the:
[v] Enable username password based authentication (ALLOW_USER_PASSWORD_AUTH)
Leave Radio buttons as is:
o Enabled (Recommended)
Screenshot:
press [create app client]
3) copy and keep the 'App client id'
this is a string format similar to 5psjts111111117jclis0mu28q
Screenshot:
4) left panel menu->App Client settings
Enabled Identity Providers: [v]Select all
[v] Cognito User Pool
Callback URL(s): put the api gw url or https://www.google.com/
OAuth 2.0
Allowed OAuth Flows
[v] Implicit grant
Allowed OAuth Scopes
[v] openid
Screenshot:
5) left panel menu->Domain name
put a string in the prefix field, for instance: music123456789
check if available using the 'check' button.
your domain now is: https://music123456789.auth.us-east-1.amazoncognito.com
Screenshot:
6) left panel menu->Users and Groups
press [Create user]
Username (Required): Your.Mail#company.com
clear all [v] check boxes
Temporary password: Xx123456!
eMail: Your.Mail#company.com
7) in POSTMAN
Press new Request
enter the 'Authorization' tab
Select TYPE: OAuth 2.0
press the [Get new Access Token] button and fill in:
Token Name: myToken123
Grant Type: select 'implicit' from the listbox
callback URL: https://www.google.com/
(as in clause 4 or in cognito console->App Integration->App client settings)
Auth URL: https://music123456789.auth.us-east-1.amazoncognito.com/login
(as in clause 5 + '/login' suffix, what you have defined in cognito
console->App Integration->Domain Name)
Client ID: 5psjts343gm7gm7jclis0mu28q (the app client id - as in 3,
what you have defined in cognito console->General Settings->App clients)
Scope: openid (as in 4, what you have defined in cognito console->App
client settings->Allowed OAuth Scopes)
COGNITO to OKTA idp configuration
When connecting Cognito to Okta IDP, Configuration should be as follows:
Okta Setup
Cognito Setup
Postman setup
As an addition to very through explanations of Robert Jordan and ylev, I made it work by using the id_token instead of the Access Token.
In the token details page, copy the id_token and add it to the header manually without Bearer prefix:
Source: https://github.com/postmanlabs/postman-app-support/issues/6987
For those wanting to move away from the deprecated "implicit" grant to the recommended "authorization" aka "authorization code" grant, you'll want to have the following in Postman:
Grant Type: Authorization Code (Authorization Code with PKCE would prevent the code from being used by anyone else if it were intercepted in transit but either or... you probably want to start with getting "Authorization Code" working.)
Callback URL: https://oauth.pstmn.io/v1/callback (or whatever Postman sets it to when you check "Authorize using browser"
Auth URL: https://{app name you chose when creating the custom auth domain}.auth.{aws region}.amazoncognito.com/login e.g. https://myapp.auth.us-east-1.amazoncognito.com/login. You can find this in AWS Console -> Cognito -> the user pool -> App Integration tab -> Domain section -> Cognito domain (use the Actions dropdown to create a custom domain if you don't already have one).
Access Token URL: https://{app name}.auth.{aws region}.amazoncognito.com/oauth2/token e.g. https://myapp.auth.us-east-1.amazoncognito.com/oauth2/token.
Client ID: The Client ID corresponding to the "App Client" (e.g. the web app users will be authenticating through Cognito to use), found in AWS Console -> Cognito -> the user pool -> App Integration tab -> App Client List section -> the App Client.
Client Secret: An optional added security measure. This should never be sent to the web app as the client secret could then be extracted by a nefarious user via Chrome Dev Tools or the like. You can (and should) however use Client Secret with backend applications e.g. the API service backing your frontend web app. This is a decision that has to be made in AWS when the App Client is created within the Cognito User Pool, but don't fret- App Clients are easy to create/delete/recreate if you change your mind or pick the wrong setting.
Scope: OAuth uses "scopes" as a means of defining what the application which holds and uses the access token (e.g. some web app) can do/access on behalf of the user whose account it's using. It's similar to authorization in a web app (e.g. only users in the "admin" group can access the settings page) but it's meant to be authorization with respect to a user's metadata, so typically that manifests as user metadata the app has access to, for example the user's calendar or contacts or phone number. OAuth scope is not meant to replace an app's authorization system (e.g. RBAC) so if you're just making some web app and just need Cognito to handle user signup, storing and resetting passwords for users, etc. you can more or less ignore OAuth "scope", though you should probably be setting the "Scope" value in Postman to something like "openid email" (Scopes are separated by a single space and you can't request and obtain the "email" scope without also requesting "openid") so you at least get the user's email address in the access token to compare with your "Users" table in your app's database. Scope makes more sense and becomes more relevant in a scenario where your web app is authenticating with an actual third-party (not your own Cognito user pool), like Facebook or Google. Maybe you're making an app that syncs users' friends' contact data from Facebook to.. I don't know, a CSV file downloaded to your computer for backup purposes. In this case you want to request from Facebook's OAuth server the "friends-list" scope or whatever Facebook decided to call that scope. On the other hand, if you just need Facebook as a means for allowing your users to easily sign in to your app without having to create an account, you don't need the "friends-list" or any other scope from Facbeook (maybe just the scope that gives you the user's email address?).
Other fields:
Client Authentication: Send client credentials in body
Type: OAuth 2.0
Add authorization data to: Request Headers
Sources:
https://www.czetsuyatech.com/2021/01/aws-generate-cognito-access-token.html
https://aws.amazon.com/blogs/mobile/understanding-amazon-cognito-user-pool-oauth-2-0-grants/
https://api.slack.com/legacy/oauth-scopes
If your client supports USER_PASSWORD_AUTH you can request valid bearer tokens using the aws client.
read -s -p "Password: " && \
aws cognito-idp initiate-auth \
--client-id <client id> \
--auth-flow USER_PASSWORD_AUTH \
--auth-parameters "USERNAME=<username>,PASSWORD=$REPLY"
This can be added to Postman under Authorization / Type: Bearer Token.
For Postman 8.5.1 and AWS Chalice + Cognito user pool on the backend I have working example:
Cognito > User pools > > App integration > App client settings
About vars:
{{cognito_callback_url}} - Your Callback URL(s) from App client
settings
{{cognito_auth_url}} - Cognito > User pools >
> App integration > Domain name + /login
(https://.....auth.ap-south-1.amazoncognito.com/login)
{{cognito_client_id}} - Your App client web id from App client
settings
{{cognito_scope}} - Use 'openid'
Now click the Get the new access token in the bottom and authorize yourself using existing user data from pool
I thought i would post some more information about using cognito with an elastic load balancer. AWS load balancers do not current support auth via headers :( you can get it working on postman by copying cookies from a successfull web request into the postman request
The use-case you want to implement can be achieved by using the OAuth 2.0 authorization. If you can get the Auth URL/ Access Token URL, Client ID, and the Client Secret- you should be able to do it.
Here's a link to the documentation of the various authorization types we support including the above mentioned one- https://www.getpostman.com/docs/v6/postman/sending_api_requests/authorization.
Cheers.
My Current Setup
Google Cloud Endpoints hosted on Google App Engine.
Google Echo Tutorial (https://cloud.google.com/endpoints/docs/frameworks/python/get-started-frameworks-python)
Python local server making requests to the echo API.
The echo tutorial is up and running. I can make calls to open endpoints and the one requiring an API key using a python script on my machine. I have not been able to make an authorized API call with a Google ID token. None of the Google examples have worked so far.
From my understanding, the workflow should be
Use a key file to authorize the service account to generate a JWT.
Use the JWT to generate a Google ID token.
Google Example: https://cloud.google.com/endpoints/docs/openapi/service-account-authentication#using_a_google_id_token (Key File)
The code fails. Function get_id_token() return res['id_token'] fails with no id_token in res.
Has anyone gotten the example to work? Does anyone have an example of making an authorized API call to an Endpoint API with a Google ID token from a service account?
The main issue was generating the JWT and the code that works for me is below. I have yet to find a better way to do this that works. If you know of a better way please submit your answers below or add a comment. The code that generates the Google ID Token from JWT is exactly from Google documentation here (https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/endpoints/getting-started/clients/service_to_service_google_id_token/main.py) get_id_token function.
def generate_jwt(audience, json_keyfile, service_account_email):
"""Generates a signed JSON Web Token using a Google API Service Account.
https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/endpoints/getting-started/clients/google-jwt-client.py
"""
# Note: this sample shows how to manually create the JWT for the purposes
# of showing how the authentication works, but you can use
# google.auth.jwt.Credentials to automatically create the JWT.
# http://google-auth.readthedocs.io/en/latest/reference/google.auth.jwt.html#google.auth.jwt.Credentials
signer = google.auth.crypt.RSASigner.from_service_account_file(json_keyfile)
now = int(time.time())
expires = now + 3600 # One hour in seconds
payload = {
'iat': now,
'exp': expires,
'aud': 'https://www.googleapis.com/oauth2/v4/token',
# target_audience must match 'audience' in the security configuration in your
# openapi spec. It can be any string.
'target_audience': audience,
'iss': service_account_email
}
jwt = google.auth.jwt.encode(signer, payload)
return jwt