Programmatic authentication

This page describes how to authenticate to a 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. Read about user account credentials.
  • 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. Learn how to understand service accounts.

Before you begin

Before you begin, you'll need the following:

  • A 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 a IAP-secured resource.

Authenticating from a mobile app

  1. Create an OAuth 2.0 client ID for your mobile app in the same project as the IAP-secured resource:
    1. Go to the Credentials page.
      Go to the Credentials page
    2. Select the project with the IAP-secured resource.
    3. Click Create credentials, then select OAuth Client ID.
    4. Select the Application type for which you want to create credentials.
    5. Add a Name and Restrictions if appropriate, then click Create.
  2. On the OAuth client window that appears, note the Client ID for the IAP-secured resource you want to connect to.
  3. Get an ID token for the IAP-secured client ID:
  4. 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.

Setting up the client ID

To allow developers to access your application from the command line, you'll first need to create OAuth client ID credentials of type Other:

  1. Go to the Credentials page.
    Go to the Credentials page
  2. Select the project with the IAP-secured resource.
  3. Click Create credentials, then select OAuth Client ID.
  4. Under Application type, select Other, add a Name, then click Create.
  5. On the OAuth client window that appears, note the client ID and client secret. You'll need to use these in a script to manage credentials or otherwise share with your developers.
  6. On the Credentials window, your new Other credentials appear along with the primary client ID that's used to access your application.

Signing in to the application

Each developer who wants to access a IAP-secured app will need to sign in first. You can package the process into a script, such as by using Cloud SDK. Following is an example using curl to sign in and generate a token that can be used to access the application:

  1. Sign in to your account that has access to the Google Cloud resource.
  2. Go to the following URI where OTHER_CLIENT_ID is the Other client ID you created above:

  3. In the window that appears, note the Authorization code to replace AUTH_CODE below along with the Other client ID and secret you created above:

    curl --verbose \
          --data client_id=OTHER_CLIENT_ID \
          --data client_secret=OTHER_CLIENT_SECRET \
          --data code=AUTH_CODE \
          --data redirect_uri=urn:ietf:wg:oauth:2.0:oob \
          --data grant_type=authorization_code \

    This code returns a JSON object with a refresh_token field that you can save as a login token to access the application.

Accessing the application

To access the application, you'll exchange the refresh_token you generated during the sign-in flow for an ID token. The ID token is valid for about one hour, during which time you can make multiple requests to a specific app. Following is an example using curl to use the token and access the application:

  1. Use the code below where REFRESH_TOKEN is the token from the sign-in flow, IAP_CLIENT_ID is the primary client ID used to access your application, and OTHER_CLIENT_ID and OTHER_CLIENT_SECRET are the client ID and secret you created when you set up the client ID above:

    curl --verbose \
          --data client_id=OTHER_CLIENT_ID \
          --data client_secret=OTHER_CLIENT_SECRET \
          --data refresh_token=REFRESH_TOKEN \
          --data grant_type=refresh_token \
          --data audience=IAP_CLIENT_ID \

    This code returns a JSON object with an id_token field that you can use to access the app.

  2. To access the app, use the id_token as follows:

    curl --verbose --header 'Authorization: Bearer ID_TOKEN' URL

Authenticating from a service account

Use an OpenID Connect (OIDC) token to authenticate a service account to a IAP-secured resource.

  1. Add the service account to the access list for the IAP-secured project.
  2. Generate a JWT-based access token. This uses a target_audience additional claim that requires a client ID. To find your client ID, follow the steps below:

    1. Go to the IAP page.
    2. Find the resource you want to access, then click More > Edit OAuth Client.
      edit OAuth client on the More menu

    3. On the Credentials page that appears, note the client ID.

  3. Request an OIDC token for the IAP-secured client ID.

  4. Include the OIDC token in an Authorization: Bearer header to make the authenticated request to the IAP-secured resource.

The following sample code authenticates the default service account to a IAP-secured resource:


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Threading;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Requests;
using Google.Apis.Json;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;

namespace GoogleCloudSamples
    class IAPClient
        /// <summary>
        /// Authenticates using the client id and credentials, then fetches
        /// the uri.
        /// </summary>
        /// <param name="iapClientId">The client id observed on 
        /// <param name="credentialsFilePath">Path to the credentials .json file
        /// download from
        /// </param>
        /// <param name="uri">HTTP uri to fetch.</param>
        /// <returns>The http response body as a string.</returns>
        public static string InvokeRequest(string iapClientId,
            string credentialsFilePath, string uri)
            // Read credentials from the credentials .json file.
            ServiceAccountCredential saCredential;
            using (var fs = new FileStream(credentialsFilePath,
                FileMode.Open, FileAccess.Read))
                saCredential = ServiceAccountCredential

            // Generate a JWT signed with the service account's private key 
            // containing a special "target_audience" claim.
            var jwtBasedAccessToken =
                CreateAccessToken(saCredential, iapClientId);

            // Request an OIDC token for the Cloud IAP-secured client ID.
            var req = new GoogleAssertionTokenRequest()
                Assertion = jwtBasedAccessToken
            var result = req.ExecuteAsync(saCredential.HttpClient,
                saCredential.TokenServerUrl, CancellationToken.None,
            string token = result.IdToken;

            // Include the OIDC token in an Authorization: Bearer header to 
            // IAP-secured resource
            var httpClient = new HttpClient();
            httpClient.DefaultRequestHeaders.Authorization =
                new AuthenticationHeaderValue("Bearer", token);
            string response = httpClient.GetStringAsync(uri).Result;
            return response;

        /// <summary>
        /// Generate a JWT signed with the service account's private key 
        /// containing a special "target_audience" claim.
        /// </summary>
        /// <param name="privateKey">The private key string pulled from
        /// a credentials .json file.</param>
        /// <param name="iapClientId">The client id observed on 
        /// <param name="email">The e-mail address associated with the
        /// privateKey.</param>
        /// <returns>An access token.</returns>
        static string CreateAccessToken(ServiceAccountCredential saCredential,
            string iapClientId)
            var now = saCredential.Clock.UtcNow;
            var currentTime = ToUnixEpochDate(now);
            var expTime = ToUnixEpochDate(now.AddHours(1));

            var claims = new[]
                new Claim(JwtRegisteredClaimNames.Aud,
                new Claim(JwtRegisteredClaimNames.Sub, saCredential.Id),
                new Claim(JwtRegisteredClaimNames.Iat, currentTime.ToString()),
                new Claim(JwtRegisteredClaimNames.Exp, expTime.ToString()),
                new Claim(JwtRegisteredClaimNames.Iss, saCredential.Id),

                // We need to generate a JWT signed with the service account's 
                // private key containing a special "target_audience" claim. 
                // That claim should contain the clientId of IAP we eventually
                // want to access.
                new Claim("target_audience", iapClientId)

            // Encryption algorithm must be RSA SHA-256, according to
            var signingCredentials = new SigningCredentials(
                new RsaSecurityKey(saCredential.Key),
            var token = new JwtSecurityToken(
                claims: claims,
                signingCredentials: signingCredentials);
            return new JwtSecurityTokenHandler().WriteToken(token);

        static long ToUnixEpochDate(DateTime date)
              => (long)Math.Round((date.ToUniversalTime() -
                                   new DateTimeOffset(1970, 1, 1, 0, 0, 0,


import java.time.Clock;
import java.util.Collections;

public class BuildIapRequest {
  private static final String IAM_SCOPE = "";
  private static final String OAUTH_TOKEN_URI = "";
  private static final String JWT_BEARER_TOKEN_GRANT_TYPE =
  private static final long EXPIRATION_TIME_IN_SECONDS = 3600L;

  private static final HttpTransport httpTransport = new NetHttpTransport();

  private static Clock clock = Clock.systemUTC();

  private BuildIapRequest() {}

  private static IdTokenProvider getIdTokenProvider() throws Exception {
    GoogleCredentials credentials =
    // service account credentials are required to sign the jwt token
    if (credentials == null || !(credentials instanceof IdTokenProvider)) {
      throw new Exception("Google credentials : credentials that can provide id tokens expected");
    return (IdTokenProvider) credentials;

   * Clone request and add an IAP Bearer Authorization header with signed JWT token.
   * @param request Request to add authorization header
   * @param iapClientId OAuth 2.0 client ID for IAP protected resource
   * @return Clone of request with Bearer style authorization header with signed jwt token.
   * @throws Exception exception creating signed JWT
  public static HttpRequest buildIapRequest(HttpRequest request, String iapClientId)
      throws Exception {

    IdTokenProvider idTokenProvider = getIdTokenProvider();
    IdTokenCredentials credentials = IdTokenCredentials.newBuilder()

    HttpRequestInitializer httpRequestInitializer = new HttpCredentialsAdapter(credentials);

    return httpTransport
        .buildRequest(request.getRequestMethod(), request.getUrl(), request.getContent());


 * TODO(developer): Uncomment these variables before running the sample.
// const url = 'https://some.iap.url';
// const targetAudience = '';

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

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

request().catch(err => {
  process.exitCode = 1;


namespace Google\Cloud\Samples\Iap;

# Imports Auth libraries and Guzzle HTTP libraries.
use Google\Auth\ApplicationDefaultCredentials;
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;

 * Make a request to an application protected by Identity-Aware Proxy.
 * @param string $url The Identity-Aware Proxy-protected URL to fetch.
 * @param string $clientId The client ID used by Identity-Aware Proxy.
 * @return The response body.
function make_iap_request($url, $clientId)
    // create middleware, using the client ID as the target audience for IAP
    $middleware = ApplicationDefaultCredentials::getIdTokenMiddleware($clientId);
    $stack = HandlerStack::create();

    // create the HTTP client
    $client = new Client([
        'handler' => $stack,
        'auth' => 'google_auth'

    // make the request
    return $client->get($url);


import google.auth
import google.auth.app_engine
import google.auth.compute_engine.credentials
import google.auth.iam
from google.auth.transport.requests import Request
import google.oauth2.credentials
import google.oauth2.service_account
import requests
import requests_toolbelt.adapters.appengine


def make_iap_request(url, client_id, method='GET', **kwargs):
    """Makes a request to an application protected by Identity-Aware Proxy.

      url: The Identity-Aware Proxy-protected URL to fetch.
      client_id: The client ID used by Identity-Aware Proxy.
      method: The request method to use
              ('GET', 'OPTIONS', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE')
      **kwargs: Any of the parameters defined for the request function:
                If no timeout is provided, it is set to 90 by default.

      The page body, or raises an exception if the page couldn't be retrieved.
    # Set the default timeout, if missing
    if 'timeout' not in kwargs:
        kwargs['timeout'] = 90

    # Figure out what environment we're running in and get some preliminary
    # information about the service account.
    bootstrap_credentials, _ = google.auth.default(
    if isinstance(bootstrap_credentials,
        raise Exception('make_iap_request is only supported for service '
    elif isinstance(bootstrap_credentials,

    # For service account's using the Compute Engine metadata service,
    # service_account_email isn't available until refresh is called.

    signer_email = bootstrap_credentials.service_account_email
    if isinstance(bootstrap_credentials,
        # Since the Compute Engine metadata service doesn't expose the service
        # account key, we use the IAM signBlob API to sign instead.
        # In order for this to work:
        # 1. Your VM needs the scope.
        #    You can specify this specific scope when creating a VM
        #    through the API or gcloud. When using Cloud Console,
        #    you'll need to specify the "full access to all Cloud APIs"
        #    scope. A VM's scopes can only be specified at creation time.
        # 2. The VM's default service account needs the "Service Account Actor"
        #    role. This can be found under the "Project" category in Cloud
        #    Console, or roles/iam.serviceAccountActor in gcloud.
        signer = google.auth.iam.Signer(
            Request(), bootstrap_credentials, signer_email)
        # A Signer object can sign a JWT using the service account's key.
        signer = bootstrap_credentials.signer

    # Construct OAuth 2.0 service account credentials using the signer
    # and email acquired from the bootstrap credentials.
    service_account_credentials = google.oauth2.service_account.Credentials(
        signer, signer_email, token_uri=OAUTH_TOKEN_URI, additional_claims={
            'target_audience': client_id

    # service_account_credentials gives us a JWT signed by the service
    # account. Next, we use that to obtain an OpenID Connect token,
    # which is a JWT signed by Google.
    google_open_id_connect_token = get_google_open_id_connect_token(

    # Fetch the Identity-Aware Proxy-protected URL, including an
    # Authorization header containing "Bearer " followed by a
    # Google-issued OpenID Connect token for the service account.
    resp = requests.request(
        method, url,
        headers={'Authorization': 'Bearer {}'.format(
            google_open_id_connect_token)}, **kwargs)
    if resp.status_code == 403:
        raise Exception('Service account {} does not have permission to '
                        'access the IAP-protected application.'.format(
    elif resp.status_code != 200:
        raise Exception(
            'Bad response from application: {!r} / {!r} / {!r}'.format(
                resp.status_code, resp.headers, resp.text))
        return resp.text

def get_google_open_id_connect_token(service_account_credentials):
    """Get an OpenID Connect token issued by Google for the service account.

    This function:

      1. Generates a JWT signed with the service account's private key
         containing a special "target_audience" claim.

      2. Sends it to the OAUTH_TOKEN_URI endpoint. Because the JWT in #1
         has a target_audience claim, that endpoint will respond with
         an OpenID Connect token for the service account -- in other words,
         a JWT signed by *Google*. The aud claim in this JWT will be
         set to the value from the target_audience claim in #1.

    For more information, see .
    The HTTP/REST example on that page describes the JWT structure and
    demonstrates how to call the token endpoint. (The example on that page
    shows how to get an OAuth2 access token; this code is using a
    modified version of it to get an OpenID Connect token.)

    service_account_jwt = (
    request = google.auth.transport.requests.Request()
    body = {
        'assertion': service_account_jwt,
        'grant_type': google.oauth2._client._JWT_GRANT_TYPE,
    token_response = google.oauth2._client._token_endpoint_request(
        request, OAUTH_TOKEN_URI, body)
    return token_response['id_token']

What's next