This page describes how to authenticate to an Identity-Aware Proxy (IAP)-secured resource from a user account or a service account.
A user account belongs to an individual user. You authenticate a user account when your application requires access to IAP-secured resources on a user's behalf. For more information, see User accounts.
A service account belongs to an application instead of an individual user. You authenticate a service account when you want to allow an application to access your IAP-secured resources. For more information, see Service accounts.
Before you begin
Before you begin, you'll need the following:
- An IAP-secured application to which you want to programmatically connect using a developer account, service account, or mobile app credentials.
Authenticating a user account
You can enable user access to your app from a desktop or mobile app to allow a program to interact with an IAP-secured resource.
Authenticating from a mobile app
- Create or use an existing OAuth 2.0 client ID for your mobile app. To use an existing OAuth 2.0 client ID, follow the steps in How to share OAuth Clients.
- Allowlist the OAuth client ID for programmatic access for the application.
- Get an ID token for the IAP-secured client ID.
- Android: Use the
Google Sign-In API to request
an
OpenID Connect
(OIDC) token. Set the
requestIdToken
client ID to the client ID for the resource you're connecting to. - iOS: Use Google Sign-In to get an ID token.
- Android: Use the
Google Sign-In API to request
an
OpenID Connect
(OIDC) token. Set the
- Include the ID token in an
Authorization: Bearer
header to make the authenticated request to the IAP-secured resource.
Authenticating from a desktop app
This section describes how to authenticate a user account from a desktop command line.
- To allow developers to access your application from the command line, create a desktop OAuth 2.0 client ID or share an existing desktop OAuth client ID.
- Allowlist the OAuth client ID for programmatic access for the application.
Signing in to the application
Each developer who wants to access an IAP-secured app will need to sign in first. You can package the process into a script, such as by using gcloud CLI. Following is an example using curl to sign in and generate a token that can be used to access the application:
- Sign in to your account that has access to the Google Cloud resource.
-
Start a local server that can echo the incoming requests.
NOTE: The command uses the NetCat utility. You can use the utility of your choice.$ nc -k -l 4444
-
Go to the following URI where
DESKTOP_CLIENT_ID
is the Desktop app client ID:https://accounts.google.com/o/oauth2/v2/auth?client_id=DESKTOP_CLIENT_ID&response_type=code&scope=openid%20email&access_type=offline&redirect_uri=http://localhost:4444&cred_ref=true
-
In the local server output, look for the request parameters. You should see
something like the following:
GET /?code=$CODE&scope=email%20openid%20https://www.googleapis.com/auth/userinfo.email&hd=google.com&prompt=consent HTTP/1.1
copy the CODE to replaceAUTH_CODE
below along with the Desktop app client ID and secret:curl --verbose \ --data client_id=DESKTOP_CLIENT_ID \ --data client_secret=DESKTOP_CLIENT_SECRET \ --data code=AUTH_CODE \ --data redirect_uri=http://localhost:4444 \ --data grant_type=authorization_code \ https://oauth2.googleapis.com/token
This code returns a JSON object with an
id_token
field that you can use to access the application.
Accessing the application
To access the app, use the
id_token
as follows:
curl --verbose --header 'Authorization: Bearer ID_TOKEN' URL
Refresh Token
You can use the refresh token generated during the sign-in flow to get new ID tokens. This is useful when the original ID token expires. Each ID token is valid for about one hour, during which time you can make multiple requests to a specific app.
The following is an example using curl to use the refresh token to get a new ID
token. In the following example,
REFRESH_TOKEN
is the token
from the sign-in flow.
DESKTOP_CLIENT_ID
, and
DESKTOP_CLIENT_SECRET
are the
same as used in the sign-in flow:
curl --verbose \ --data client_id=DESKTOP_CLIENT_ID \ --data client_secret=DESKTOP_CLIENT_SECRET \ --data refresh_token=REFRESH_TOKEN \ --data grant_type=refresh_token \ https://oauth2.googleapis.com/token
This code returns a JSON object with a new
id_token
field that you can
use to access the app.
Authenticating a service account
You can use a service account JWT or an OpenID Connect (OIDC) token to authenticate a service account with an IAP-secured resource. The following table outlines some of the differences between the different authentication tokens and their features.
Authentication features | Service account JWT | OpenID Connect token |
---|---|---|
Context-aware access support | ||
OAuth 2.0 Client ID requirement | ||
Token scope | URL of IAP-secured resource | OAuth 2.0 client ID |
Authenticating with a service account JWT
Authenticating a service account using a JWT comprises the following main steps:
Grant the calling service account the Service Account Token Creator role (
roles/iam.serviceAccountTokenCreator
).The role gives principals permission to create short-lived credentials, like JWTs.
Create a JWT for the IAP-secured resource.
Sign the JWT using the service account private key.
Creating the JWT
The created JWT should have a payload similar to the following example:
{ "iss": SERVICE_ACCOUNT_EMAIL_ADDRESS, "sub": SERVICE_ACCOUNT_EMAIL_ADDRESS, "aud": TARGET_URL, "iat": IAT, "exp": EXP, }
For the
iss
andsub
fields, specify the service account's email address. This is found in theclient_email
field of the service account JSON file, or passed in. Typical format:service-account@PROJECT_ID.iam.gserviceaccount.com
For the
aud
field, specify the URL of the IAP-secured resource.For the
iat
field, specify the current Unix epoch time, and for theexp
field, specify a time within 3600 seconds later. This defines when the JWT expires.
Signing the JWT
You can use one of the following methods to sign the JWT:
- Use the IAM credentials API to sign a JWT without requiring direct access to a private key.
- Use a local credentials key file to sign the JWT locally.
Signing the JWT using IAM Service Account Credentials API
Use the IAM Service Account Credentials API to sign a service account JWT. The method fetches the private key associated with your service account and uses it to sign the JWT payload. This allows the signing of a JWT without direct access to a private key.
To authenticate to IAP, set up Application Default Credentials. For more information, see Set up authentication for a local development environment.
gcloud
Run the following command to prepare a request with the JWT payload:
cat > claim.json << EOM { "iss": "SERVICE_ACCOUNT_EMAIL_ADDRESS", "sub": "SERVICE_ACCOUNT_EMAIL_ADDRESS", "aud": "TARGET_URL", "iat": $(date +%s), "exp": $((`date +%s` + 3600)) } EOM
Use the following Google Cloud CLI command to sign the payload in
request.json
:gcloud iam service-accounts sign-jwt --iam-account=SERVICE_ACCOUNT_EMAIL_ADDRESS claim.json output.jwt
Upon a successful request,
output.jwt
contains a signed JWT.Use the JWT to access your IAP-secured resource.
Python
import datetime
import json
import google.auth
from google.cloud import iam_credentials_v1
import jwt
def generate_jwt_payload(service_account_email: str, resource_url: str) -> str:
"""Generates JWT payload for service account.
The resource url provided must be the same as the url of the IAP secured resource.
Args:
service_account_email (str): Specifies service account JWT is created for.
resource_url (str): Specifies scope of the JWT, the URL that the JWT will be allowed to access.
Returns:
A signed-jwt that can be used to access IAP protected applications.
Access the application with the JWT in the Authorization Header.
curl --verbose --header 'Authorization: Bearer SIGNED_JWT' URL
"""
iat = datetime.datetime.now(tz=datetime.timezone.utc)
exp = iat + 3600
return json.dumps({
'iss': service_account_email,
'sub': service_account_email,
'aud': resource_url,
'iat': iat,
'exp': exp,
})
def sign_jwt(target_sa: str, resource_url: str) -> str:
"""Signs JWT payload using ADC and IAM credentials API.
Args:
target_sa (str): Service Account JWT is being created for.
iap.webServiceVersions.accessViaIap permission is required.
resource_url (str): Audience of the JWT, and scope of the JWT token.
This is the url of the IAP protected application.
Returns:
A signed-jwt that can be used to access IAP protected apps.
"""
source_credentials, _ = google.auth.default()
iam_client = iam_credentials_v1.IAMCredentialsClient(credentials=source_credentials)
return iam_client.sign_jwt(
name=iam_client.service_account_path('-', target_sa),
payload=generate_jwt_payload(target_sa, resource_url),
).signed_jwt
Upon a successful request, the script returns a signed JWT. Use the JWT to access your IAP-secured resource.
curl
Run the following command to prepare a request with the JWT payload:
cat << EOF > request.json { "payload": JWT_PAYLOAD } EOF
Sign the JWT using the IAM Service Account Credentials API:
curl -X POST \ -H "Authorization: Bearer $(gcloud auth print-access-token)" \ -H "Content-Type: application/json; charset=utf-8" \ -d @request.json \ "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/SERVICE_ACCOUNT_EMAIL_ADDRESS:signJwt"
Upon a successful request, a signed JWT is in the response.
Use the JWT to access your IAP-secured resource.
Signing the JWT from a local credential key file
JWTs are signed using the private key of the service account.
If you have a service account key file, the JWT can be signed locally.
The script sends a JWT header along with the payload. For the kid
field in the header, use the service account's private key ID, which is in the
private_key_id
field of the service account credential JSON file.
The key is also used to sign the JWT.
Python
import time
import jwt
import json
def generate_jwt_payload(service_account_email, resource_url):
"""Generates JWT payload for service account.
The resource url provided must be the same as the url of the IAP secured resource.
Args:
service_account_email (str): Specifies service account JWT is created for.
resource_url (str): Specifies scope of the JWT, the URL that the JWT will be allowed to access.
Returns:
A signed-jwt that can be used to access IAP protected applications.
Access the application with the JWT in the Authorization Header.
curl --verbose --header 'Authorization: Bearer SIGNED_JWT' URL
"""
iat = datetime.datetime.now(tz=datetime.timezone.utc)
exp = iat + 3600
return json.dumps({
'iss': service_account_email,
'sub': service_account_email,
'aud': resource_url,
'iat': iat,
'exp': exp,
})
def sign_jwt_with_key_file(credential_key_file_path, resource_url):
"""Signs JWT payload using local service account credential key file.
Args:
credential_key_file_path (str): Path to the downloaded JSON credentials of the service
account the JWT is being created for.
resource_url (str): Scope of JWT token, This is the url of the IAP protected application.
Returns:
A service account JWT created with a downloaded private key.
"""
with open(credential_key_file_path, 'r') as credential_key_file:
key_data = json.load(credential_key_file)
PRIVATE_KEY_ID_FROM_JSON = key_data["private_key_id"]
PRIVATE_KEY_FROM_JSON = key_data["private_key"]
SERVICE_ACCOUNT_EMAIL = key_data["client_email"]
# Sign JWT with private key and store key id in the header
additional_headers = {'kid': PRIVATE_KEY_ID_FROM_JSON}
payload = generate_jwt_payload(service_account_email=SERVICE_ACCOUNT_EMAIL, resource_url=resource_url)
signed_jwt = jwt.encode(
payload,
PRIVATE_KEY_FROM_JSON,
headers=additional_headers,
algorithm='RS256',
)
return signed_jwt
A signed JWT is the result.
Accessing the application
In all cases, to access the app, use the
signed-jwt
as follows:
curl --verbose --header 'Authorization: Bearer SIGNED_JWT' URL
Authenticating with an OIDC token
- Create or use an existing OAuth 2.0 client ID. To use an existing OAuth 2.0 client ID, follow the steps in How to share OAuth Clients.
- Allowlist the OAuth client ID for programmatic access for the application.
You also need to add the service account to the access list
for the IAP-secured project. The following code samples show
how to obtain an OIDC token. You must include
the token in an Authorization: Bearer
header to make the authentication request
to the IAP-secured resource.
Obtaining an OIDC token for the default service account
If you want to get an OIDC token for the default service account for Compute Engine, App Engine, or Cloud Run, you can use the following code sample to generate the token to access an IAP-secured resource:
C#
Go
To authenticate to IAP, set up Application Default Credentials. For more information, see Set up authentication for a local development environment.
Java
Node.js
PHP
To authenticate to IAP, set up Application Default Credentials. For more information, see Set up authentication for a local development environment.
Python
To authenticate to IAP, set up Application Default Credentials. For more information, see Set up authentication for a local development environment.
Ruby
To authenticate to IAP, set up Application Default Credentials. For more information, see Set up authentication for a local development environment.
Obtaining an OIDC token from a local service account key file
If you have a service account key file, you can adapt the preceding code samples to provide the service account key file.
Bash
#!/usr/bin/env bash
set -euo pipefail
get_token() {
# Get the bearer token in exchange for the service account credentials.
local service_account_key_file_path="${1}"
local iap_client_id="${2}"
local iam_scope="https://www.googleapis.com/auth/iam"
local oauth_token_uri="https://www.googleapis.com/oauth2/v4/token"
local private_key_id="$(cat "${service_account_key_file_path}" | jq -r '.private_key_id')"
local client_email="$(cat "${service_account_key_file_path}" | jq -r '.client_email')"
local private_key="$(cat "${service_account_key_file_path}" | jq -r '.private_key')"
local issued_at="$(date +%s)"
local expires_at="$((issued_at + 600))"
local header="{'alg':'RS256','typ':'JWT','kid':'${private_key_id}'}"
local header_base64="$(echo "${header}" | base64)"
local payload="{'iss':'${client_email}','aud':'${oauth_token_uri}','exp':${expires_at},'iat':${issued_at},'sub':'${client_email}','target_audience':'${iap_client_id}'}"
local payload_base64="$(echo "${payload}" | base64)"
local signature_base64="$(printf %s "${header_base64}.${payload_base64}" | openssl dgst -binary -sha256 -sign <(printf '%s\n' "${private_key}") | base64)"
local assertion="${header_base64}.${payload_base64}.${signature_base64}"
local token_payload="$(curl -s \
--data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" \
--data-urlencode "assertion=${assertion}" \
https://www.googleapis.com/oauth2/v4/token)"
local bearer_id_token="$(echo "${token_payload}" | jq -r '.id_token')"
echo "${bearer_id_token}"
}
main(){
# TODO: Replace the following variables:
SERVICE_ACCOUNT_KEY="service_account_key_file_path"
IAP_CLIENT_ID="iap_client_id"
URL="application_url"
# Obtain the ID token.
ID_TOKEN=$(get_token "${SERVICE_ACCOUNT_KEY}" "${IAP_CLIENT_ID}")
# Access the application with the ID token.
curl --header "Authorization: Bearer ${ID_TOKEN}" "${URL}"
}
main "$@"
Obtaining an OIDC token in all other cases
In all other cases, use the IAM credentials API to generate an OIDC token by impersonating a target service account right before accessing an IAP-secured resource. This process involves the following steps:
Provide the calling service account (the service account associated with the code that is obtaining the ID token) with the Service Account OpenID Connect Identity Token Creator role (
roles/iam.serviceAccountOpenIdTokenCreator
).This gives the calling service account the ability to impersonate the target service account.
Use the credentials provided by the calling service account to call the generateIdToken method on the target service account.
Set the
audience
field to your client ID.
For step-by-step instructions, see Create an ID token.
Authenticating from Proxy-Authorization Header
If your application uses the Authorization
request header, you can
include the ID token in a Proxy-Authorization: Bearer
header instead. If a
valid ID token is found in a Proxy-Authorization
header,
IAP authorizes the request with it. After authorizing the
request, IAP passes the Authorization
header to your
application without processing the content.
If no valid ID token is found in the Proxy-Authorization
header,
IAP continues to process the Authorization
header and
strips the Proxy-Authorization
header before passing the request to your
application.
What's next
- Learn more about Authorization: Bearer Tokens.
- Try Sign-In for Android or Sign-In for iOS.