Programmatic authentication

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. 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 Desktop app:

  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 Desktop app, 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 Desktop app 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 DESKTOP_CLIENT_ID is the Desktop app client ID you created above:

    https://accounts.google.com/o/oauth2/v2/auth?client_id=DESKTOP_CLIENT_ID&response_type=code&scope=openid%20email&access_type=offline&redirect_uri=urn:ietf:wg:oauth:2.0:oob

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

    curl --verbose \
          --data client_id=DESKTOP_CLIENT_ID \
          --data client_secret=DESKTOP_CLIENT_SECRET \
          --data code=AUTH_CODE \
          --data redirect_uri=urn:ietf:wg:oauth:2.0:oob \
          --data grant_type=authorization_code \
          https://oauth2.googleapis.com/token

    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 DESKTOP_CLIENT_ID and DESKTOP_CLIENT_SECRET are the client ID and secret you created when you set up the client ID above:

    curl --verbose \
          --data client_id=DESKTOP_CLIENT_ID \
          --data client_secret=DESKTOP_CLIENT_SECRET \
          --data refresh_token=REFRESH_TOKEN \
          --data grant_type=refresh_token \
          --data audience=IAP_CLIENT_ID \
          https://oauth2.googleapis.com/token

    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. Follow these steps to find your client ID:

  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.

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. No matter which one you choose, you need to include the token in an Authorization: Bearer header to make the authenticated 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 a IAP-secured resource:

C#


using Google.Apis.Auth.OAuth2;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;

public class IAPClient
{
    /// <summary>
    /// Makes a request to a IAP secured application by first obtaining
    /// an OIDC token.
    /// </summary>
    /// <param name="iapClientId">The client ID observed on 
    /// https://console.cloud.google.com/apis/credentials. </param>
    /// <param name="uri">HTTP URI to fetch.</param>
    /// <param name="cancellationToken">The token to propagate operation cancel notifications.</param>
    /// <returns>The HTTP response message.</returns>
    public async Task<HttpResponseMessage> InvokeRequestAsync(
        string iapClientId, string uri, CancellationToken cancellationToken = default)
    {
        // Get the OidcToken.
        // You only need to do this once in your application
        // as long as you can keep a reference to the returned OidcToken.
        OidcToken oidcToken = await GetOidcTokenAsync(iapClientId, cancellationToken);

        // Before making an HTTP request, always obtain the string token from the OIDC token,
        // the OIDC token will refresh the string token if it expires.
        string token = await oidcToken.GetAccessTokenAsync(cancellationToken);

        // Include the OIDC token in an Authorization: Bearer header to 
        // IAP-secured resource
        // Note: Normally you would use an HttpClientFactory to build the httpClient.
        // For simplicity we are building the HttpClient directly.
        using HttpClient httpClient = new HttpClient();
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
        return await httpClient.GetAsync(uri, cancellationToken);
    }

    /// <summary>
    /// Obtains an OIDC token for authentication an IAP request.
    /// </summary>
    /// <param name="iapClientId">The client ID observed on 
    /// https://console.cloud.google.com/apis/credentials. </param>
    /// <param name="cancellationToken">The token to propagate operation cancel notifications.</param>
    /// <returns>The HTTP response message.</returns>
    public async Task<OidcToken> GetOidcTokenAsync(string iapClientId, CancellationToken cancellationToken)
    {
        // Obtain the application default credentials.
        GoogleCredential credential = await GoogleCredential.GetApplicationDefaultAsync(cancellationToken);

        // Request an OIDC token for the Cloud IAP-secured client ID.
       return await credential.GetOidcTokenAsync(OidcTokenOptions.FromTargetAudience(iapClientId), cancellationToken);
    }
}

Go

import (
	"context"
	"fmt"
	"io"
	"net/http"

	"google.golang.org/api/idtoken"
)

// makeIAPRequest makes a request to an application protected by Identity-Aware
// Proxy with the given audience.
func makeIAPRequest(w io.Writer, request *http.Request, audience string) error {
	// request, err := http.NewRequest("GET", "http://example.com", nil)
	// audience := "IAP_CLIENT_ID.apps.googleusercontent.com"
	ctx := context.Background()

	// client is a http.Client that automatically adds an "Authorization" header
	// to any requests made.
	client, err := idtoken.NewClient(ctx, audience)
	if err != nil {
		return fmt.Errorf("idtoken.NewClient: %v", err)
	}

	response, err := client.Do(request)
	if err != nil {
		return fmt.Errorf("client.Do: %v", err)
	}
	defer response.Body.Close()
	if _, err := io.Copy(w, response.Body); err != nil {
		return fmt.Errorf("io.Copy: %v", err)
	}

	return nil
}

Java


import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.auth.oauth2.IdTokenCredentials;
import com.google.auth.oauth2.IdTokenProvider;
import com.google.common.base.Preconditions;
import java.io.IOException;
import java.util.Collections;

public class BuildIapRequest {
  private static final String IAM_SCOPE = "https://www.googleapis.com/auth/iam";

  private static final HttpTransport httpTransport = new NetHttpTransport();

  private BuildIapRequest() {}

  private static IdTokenProvider getIdTokenProvider() throws IOException {
    GoogleCredentials credentials =
        GoogleCredentials.getApplicationDefault().createScoped(Collections.singleton(IAM_SCOPE));

    Preconditions.checkNotNull(credentials, "Expected to load credentials");
    Preconditions.checkState(
        credentials instanceof IdTokenProvider,
        String.format(
            "Expected credentials that can provide id tokens, got %s instead",
            credentials.getClass().getName()));

    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 IOException exception creating signed JWT
   */
  public static HttpRequest buildIapRequest(HttpRequest request, String iapClientId)
      throws IOException {

    IdTokenProvider idTokenProvider = getIdTokenProvider();
    IdTokenCredentials credentials =
        IdTokenCredentials.newBuilder()
            .setIdTokenProvider(idTokenProvider)
            .setTargetAudience(iapClientId)
            .build();

    HttpRequestInitializer httpRequestInitializer = new HttpCredentialsAdapter(credentials);

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

Node.js

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

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

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

request().catch(err => {
  console.error(err.message);
  process.exitCode = 1;
});

PHP

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();
    $stack->push($middleware);

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

    // make the request
    $response = $client->get($url);
    print('Printing out response body:');
    print($response->getBody());
}

Python

from google.auth.transport.requests import Request
from google.oauth2 import id_token
import requests


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

    Args:
      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:
                https://github.com/requests/requests/blob/master/requests/api.py
                If no timeout is provided, it is set to 90 by default.

    Returns:
      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

    # Obtain an OpenID Connect (OIDC) token from metadata server or using service
    # account.
    open_id_connect_token = id_token.fetch_id_token(Request(), client_id)

    # 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(
            open_id_connect_token)}, **kwargs)
    if resp.status_code == 403:
        raise Exception('Service account does not have permission to '
                        'access the IAP-protected application.')
    elif resp.status_code != 200:
        raise Exception(
            'Bad response from application: {!r} / {!r} / {!r}'.format(
                resp.status_code, resp.headers, resp.text))
    else:
        return resp.text

Ruby

# url = "The Identity-Aware Proxy-protected URL to fetch"
# client_id = "The client ID used by Identity-Aware Proxy"
require "googleauth"
require "faraday"

# The client ID as the target audience for IAP
id_token_creds = Google::Auth::Credentials.default target_audience: client_id

headers = {}
id_token_creds.client.apply! headers

resp = Faraday.get url, nil, headers

if resp.status == 200
  puts "X-Goog-Iap-Jwt-Assertion:"
  puts resp.body
else
  puts "Error requesting IAP"
  puts resp.status
  puts resp.headers
end

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.

Obtaining an OIDC token in all other cases

In all other cases, use the IAM credentials API to generate an OIDC token based on an access token for another service account right before accessing a IAP-secured resource:

  1. Add the account in the access token with the role service account token creator to the target account. This ensures it has the required IAM permission to create an OIDC token for the target service account.
  2. Call generateIdToken on the target service account with the access token. Pay special attention to set the audience field to your client ID.

Authenticating from Proxy-Authorization Header

If your application occupies 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