Programmatic authentication

This page describes how to authenticate to a Cloud Identity-Aware Proxy (Cloud 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 Cloud 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 Cloud IAP-secured resources. Learn how to understand service accounts.

Before you begin

Before you begin, you'll need the following:

  • A Cloud 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 Cloud 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 Cloud IAP-secured resource:
    1. Go to the Credentials page.
      Go to the Credentials page
    2. Select the project with the Cloud 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 Cloud IAP-secured resource you want to connect to.
  3. Get an ID token for the Cloud IAP-secured client ID:
  4. Include the ID token in an Authorization: Bearer header to make the authenticated request to the Cloud 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 Cloud 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 Cloud 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 GCP 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 Cloud IAP-secured resource.

  1. Add the service account to the access list for the Cloud 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 Cloud 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 Cloud IAP-secured client ID.

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

The following sample code authenticates the default service account to a Cloud 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 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']


import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSSigner;
import com.nimbusds.jose.crypto.RSASSASigner;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import java.time.Clock;
import java.time.Instant;
import java.util.Collections;
import java.util.Date;

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 ServiceAccountCredentials getCredentials() throws Exception {
    GoogleCredentials credentials =
    // service account credentials are required to sign the jwt token
    if (credentials == null || !(credentials instanceof ServiceAccountCredentials)) {
      throw new Exception("Google credentials : service accounts credentials expected");
    return (ServiceAccountCredentials) credentials;

  private static String getSignedJwt(ServiceAccountCredentials credentials, String iapClientId)
      throws Exception {
    Instant now =;
    long expirationTime = now.getEpochSecond() + EXPIRATION_TIME_IN_SECONDS;

    // generate jwt signed by service account
    // header must contain algorithm ("alg") and key ID ("kid")
    JWSHeader jwsHeader =
        new JWSHeader.Builder(JWSAlgorithm.RS256).keyID(credentials.getPrivateKeyId()).build();

    // set required claims
    JWTClaimsSet claims =
        new JWTClaimsSet.Builder()
            .claim("target_audience", iapClientId)

    // sign using service account private key
    JWSSigner signer = new RSASSASigner(credentials.getPrivateKey());
    SignedJWT signedJwt = new SignedJWT(jwsHeader, claims);

    return signedJwt.serialize();

  private static String getGoogleIdToken(String jwt) throws Exception {
    final GenericData tokenRequest =
        new GenericData().set("grant_type", JWT_BEARER_TOKEN_GRANT_TYPE).set("assertion", jwt);
    final UrlEncodedContent content = new UrlEncodedContent(tokenRequest);

    final HttpRequestFactory requestFactory = httpTransport.createRequestFactory();

    final HttpRequest request =
            .buildPostRequest(new GenericUrl(OAUTH_TOKEN_URI), content)
            .setParser(new JsonObjectParser(JacksonFactory.getDefaultInstance()));

    HttpResponse response;
    String idToken = null;
    response = request.execute();
    GenericData responseData = response.parseAs(GenericData.class);
    idToken = (String) responseData.get("id_token");
    return idToken;

   * 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 {
    // get service account credentials
    ServiceAccountCredentials credentials = getCredentials();
    // get the base url of the request URL
    String jwt = getSignedJwt(credentials, iapClientId);
    if (jwt == null) {
      throw new Exception(
          "Unable to create a signed jwt token for : "
              + iapClientId
              + "with issuer : "
              + credentials.getClientEmail());

    String idToken = getGoogleIdToken(jwt);
    if (idToken == null) {
      throw new Exception("Unable to retrieve open id token");

    // Create an authorization header with bearer token
    HttpHeaders httpHeaders = request.getHeaders().clone().setAuthorization("Bearer " + idToken);

    // create request with jwt authorization header
    return httpTransport
        .buildRequest(request.getRequestMethod(), request.getUrl(), request.getContent())


namespace Google\Cloud\Samples\Iap;

# Imports Auth libraries and Guzzle HTTP libraries.
use Google\Auth\OAuth2;
use Google\Auth\Middleware\ScopedAccessTokenMiddleware;
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, $pathToServiceAccount)
    $serviceAccountKey = json_decode(file_get_contents($pathToServiceAccount), true);
    $oauth_token_uri = '';
    $iam_scope = '';

    # Create an OAuth object using the service account key
    $oauth = new OAuth2([
        'audience' => $oauth_token_uri,
        'issuer' => $serviceAccountKey['client_email'],
        'signingAlgorithm' => 'RS256',
        'signingKey' => $serviceAccountKey['private_key'],
        'tokenCredentialUri' => $oauth_token_uri,
    $oauth->setAdditionalClaims(['target_audience' => $clientId]);

    # Obtain an OpenID Connect token, which is a JWT signed by Google.
    $token = $oauth->fetchAuthToken();
    $idToken = $oauth->getIdToken();

    # Construct a ScopedAccessTokenMiddleware with the ID token.
    $middleware = new ScopedAccessTokenMiddleware(
        function () use ($idToken) {
            return $idToken;

    $stack = HandlerStack::create();

    # Create an HTTP Client using Guzzle and pass in the credentials.
    $http_client = new Client([
        'handler' => $stack,
        'base_uri' => $url,
        'auth' => 'scoped'

    # Make an authenticated HTTP Request
    $response = $http_client->request('GET', '/', []);
    return $response;

What's next

Was this page helpful? Let us know how we did:

Send feedback about...

Identity-Aware Proxy Documentation