Application Default Credentials

This article will cover Google Cloud Application Default Credentials (ADC) and how to create credentials using various methods in PHP. I wrote another article on ADC that includes Python examples. This article is more technical and includes details directly from the Google Cloud google/auth PHP SDK with SDK source code links.

Google Cloud Application Default Credentials (ADC) are not credentials. ADC is a strategy to locate sources that contain secrets/key material to create credentials. The Google Cloud PHP SDK will search specific locations and use the first valid method to create credentials.

There are two types of identities that credentials can be created from. The first is a user identity, the second is a service account identity. You can also combine both identities to obtain impersonated credentials. For example, authenticate with a user identity and then impersonate a service account identity.

In this article, I discuss OAuth 2 and OIDC credentials. Google also supports API Keys which I do not cover. OAuth generates Access Tokens and Refresh Tokens. OIDC is a layer above OAuth that generates Identity Tokens. Since the Google SDKs manage the refresh of both Access Tokens and Identity Tokens, this article ignores Refresh Tokens. In summary, a Refresh Token is used to request a new Access Token or Identity Token as both have a lifetime. The default lifetime is 3,600 seconds (one hour).

In this article, we will use the SDK to create several example programs:

  • Create an OAuth Access Token.
  • Create an OIDC Identity Token.
  • Create a Guzzle HTTP Client to call the Compute Engine Aggregate List Instance API and display all instances in a project.
  • Create a Guzzle HTTP Client to call a Cloud Run service that requires an OIDC Identity Token from an identity authorized with the roles/run.invoker role.

ADC Search Order

The Google Cloud PHP SDK google/auth version 1.16 searches various locations to create credentials from. If all of the supported methods are not available or one is configured incorrectly, a DomainException exception is thrown.

Locations for credentials are searched in the following order:

  1. Environment variable.
  2. Well Known File.
  3. App Engine Standard: App Identity Service.
  4. Compute Engine: Metadata Service. This includes App Engine Flexible, Cloud Functions, and Cloud Run.

The source of credentials created by the above methods:

  1. Environment: Service Account.
  2. Well Known File: User Account.
  3. App Engine Standard: Service Account assigned to the service.
  4. Compute Engine: Service Account assigned to the service.

Type of tokens created by the above methods:

  1. Environment: Access and Identity Tokens.
  2. Well Known File: Access Token.
  3. App Engine Standard: Access and Identity Tokens.
  4. Compute Engine: Access and Identity Tokens.

ADC is implemented by ApplicationDefaultCredentials. [source code link] [documentation link]

The only method that requires the CLI to be installed is Well Known File. If the CLI is not installed or you have not authenticated with the application-default option, then that method will not find the file and will skip to the next method. If you need Identity Tokens, do not use Well Know File (gcloud auth application-default login). Use the Environment variable method which will be checked first. Another option is to specify the service account in your code. Use CredentialsLoader::makeCredentials(). [source code link] [documentation link]

Environment Variable

If the environment variable GOOGLE_APPLICATION_CREDENTIALS is set, ADC will use the value as the filename for secrets. This file is a Google Cloud Service Account credentials file in JSON format. The previous P12 (PFX) certificates are deprecated.

This feature is implemented by CredentialsLoader::fromEnv(). [source code link] [documentation link]

To enable this feature, create and download a Google Cloud Service Account JSON key file.

Creating and managing service account keys

This is the only ADC method that creates credentials from a service account JSON key file.

Set the environment variable GOOGLE_APPLICATION_CREDENTIALS with the value of the full path to the service account JSON key file.

Windows:

set GOOGLE_APPLICATION_CREDENTIALS=c:\path\to\service-account.json

Linux:

export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account.json"

PHP Code:

putenv("GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json");

To disable this feature, delete the environment variable.

Windows:

set GOOGLE_APPLICATION_CREDENTIALS=

Linux:

unset GOOGLE_APPLICATION_CREDENTIALS

PHP Code:

putenv("GOOGLE_APPLICATION_CREDENTIALS");

If you have added this environment variable to a shell configuration file (Linux) or the system/local environment, follow these steps:

Windows:

To permanently delete the environment variable for future sessions, edit either the system or local account environment variables. In the Windows search box enter the word environment and use the control panel to modify the system and/or local account environment variables. Delete the environment variable GOOGLE_APPLICATION_CREDENTIALS.

Linux:

To permanently delete the environment variable for future sessions, edit the shell configuration file. Delete the line setting the environment variable GOOGLE_APPLICATION_CREDENTIALS.

Typically the shell uses one or more of these files:

  • .bashrc
  • .bash_profile
  • /etc/environment
  • /etc/bash.bashrc
  • /etc/profile

Well Known File

ADC will check a known file system location that is user-specific for a JSON file created by the gcloud command-line tool.

  • On Windows, %APPDATA%/gcloud/application_default_credentials.json.
  • On other systems, $HOME/.config/gcloud/application_default_credentials.json.

This feature is implemented by CredentialsLoader::fromWellKnownFile(). [source code link] [documentation link]

To enable this feature, delete the GOOGLE_APPLICATION_CREDENTIALS environment variable (see above) and then log in with the CLI.

CLI Login

This command obtains user access credentials via a web flow and puts them in the well-known location for Application Default Credentials (ADC). [documentation link]

Note: This feature does not support generating Identity Tokens.

gcloud auth application-default login

To cancel this method:

gcloud auth application-default revoke

Note: the Well Known File created by login is deleted by revoke.

App Engine Standard

If the application is running on App Engine Standard (see Compute Engine for App Engine Flexible), the SDK will fetch a token using the AppIdentityService.

The SDK checks the server variable SERVER_SOFTWARE for the value Google App Engine and the variable APPENGINE_RUNTIME for the value php.

The SDK checks for App Engine Flexible by comparing the environment variable GAE_INSTANCE starts with the value aef-.

App Engine Standard also supports creating credentials from Environment Variables AppIdentityCredentials::fromEnv() and Well Known Locations AppIdentityCredentials::fromWellKnownFile().

This feature is provided by AppIdentityCredentials(). [source code link] [documentation link]

Compute Engine

This includes App Engine Flexible, Cloud Functions, and Cloud Run.

When you launch a compute-based service, you have the option of attaching a service account to the service. Applications running on a compute service can fetch credentials from the metadata service.

The SDK checks for the metadata service at http://169.254.169.254. The connection timeout is set to 500ms and will retry 3 times.

Compute Engine also supports creating credentials from Environment Variables GCECredentials::fromEnv() and Well Known Locations GCECredentials::fromWellKnownFile().

This feature is provided by GCECredentials(). [source code link] [documentation link]

Default Failure Condition

If none of the above methods yield credentials, throw DomainException.

Using the google/auth PHP SDK

Requirements

The PHP SDK requires installing the google/auth package. Create a new directory for the example programs. Install the package with composer:

composer require google/auth

Common SDK headers to include:

I test each program with PHP versions 7.4.21 and 8.0.6.

Each example program is self-contained. To run an example type the following command at a command/shell prompt:

PHP example1.php

SDK Class ApplicationDefaultCredentials

ApplicationDefaultCredentials. [source code link] [documentation link]

This class implements the methods for searching default locations for resources that contain secrets/keys and creating Access Tokens and/or Identity Tokens. The functions in this class are static.

Use as a static class:

Use as a traditional class:

Google OAuth Scopes

Creating an Access Token requires declaring the permissions that your token requires to call an API. In OAuth, permissions are called scopes. Google has many different scopes. [link]. Typically each API defines its own scopes.

A common Cloud Platform scope that grants broad privileges is https://www.googleapis.com/auth/cloud-platform.

Note: for Google Cloud IAM, an OAuth Scope cannot grant permissions that supersede permissions granted via IAM Roles. Scopes can request fewer permissions. If the scope requests permissions that the IAM Role does not grant, the token will be created but the permission check will fail when the token is used with an API that requires permissions that were not granted by Google Cloud IAM.

In other words, you can create a service account that has no IAM Roles attached, use a scope that requests the powerful cloud-platform scope and the token will be created. The API call will fail when the token permissions are verified.

Understanding the class methods

Create an application default credential hander. This will search the default locations and load the secrets/keys.

At this point, $credentials does not have tokens. Tokens are requested when required because they expire and require an external request to a Google Authorization Server which takes time and might fail.

To fetch an Access Token call fetchAuthToken().

$token is an associative array with three keys:

  • token_type
  • expires_in
  • access_token

token_type is the HTTP Authentication Scheme. This standard includes common types including Basic, Bearer, and Digest. Google Cloud implements the Bearer authentication scheme.

expires_in is the number of seconds until this token expires. By default, Google Cloud Access Tokens and Identity Tokens expire after 3,600 seconds (one hour).

access_token is an OAuth 2.0 Access Token. This is a hash of a JWT stored in a Google Authorization Server. An OAuth 2.0 access token is used for authenticating access to Google Cloud APIs. A Google Cloud Service (not an API service) such as Cloud Functions and Cloud Run, typically will authorize using an Open ID Connect (OIDC) Identity Token and not an OAuth Acess Token. I cover Identity Tokens in this article as well.

Now that we have a token associative array, let’s print the keys and values:

If you are using an HTTP client that requires manually creating the HTTP Authorization header, do something like this:

In this article, we will also use the Guzzle HTTP Client with Google Auth middleware to automatically handle HTTP request authorization. The Guzzle HTTP Client is the recommended/preferred method because it hides the management of tokens, requests tokens as required, and replaces expired tokens.

Google OAuth 2.0 Access Token Example Program

We covered the ApplicationDefaultCredentials basics. Let’s put this together into a program to search the default locations, load the secrets/keys, call the Google Authorization Server, and print the generated Access Token. However, I recommend starting with the basics so that you understand what the management functions are performing. This helps design better software and is important to debug problems.

Example1.php

Generate OAuth Identity Token

This class implements ADC and is almost as easy to use as the previous example. In this example, we will fetch tokens using ADC and print the Identity Token. Access to this token makes it easy to create REST API calls to services that required Identity Based Authorization such as Google Cloud Run or Cloud Functions.

Depending on the authorization requirements of the endpoint, you would typically add the HTTP header Authorization: Bearer <ID Token>.

The primary differences between example1.php and example2.php are:

  • $targetAudience – Identity tokens require an audience property to define which endpoint the token is authorized to call.
  • OAuth scopes are not used for Google OIDC Identity Tokens.
  • ApplicationDefaultCredentials::getIdTokenCredentials($targetAudience) instead of ApplicationDefaultCredentials::getCredentials($scopes).

Example2.php

In this example, I will combine example1.php and the Guzzle HTTP Client to make it easy to call Google Cloud APIs. The Guzzle HTTP Client is included with the PHP SDK.

Call the Compute Engine API method instances.aggregatedList and display details about each instance.

Example3.php

 

In this example, I wrote a Guzzle HTTP Client to call a Cloud Run service that requires an OIDC Identity Token from an identity authorized with the roles/run.invoker role.

Key items for example4.php:

  • OAuth scopes are not used for Google OIDC Identity Tokens.
  • Identity Tokens require an audience value. This is the Google Cloud Run URL found in the Google Cloud Console.
  • The identity of the credentials used by ApplicationDefaultCredentials must be authorized with the
  • roles/run.invoker role.
  • The Guzzle HTTP Client middleware is ApplicationDefaultCredentials::getIdTokenMiddleware($targetAudience).
  • The choice of the middleware determines which token type (Access or Identity) is used for the HTTP header Authorization: Bearer <TOKEN> header.

example4.php

Interesting Details

Access Tokens normally have a maximum size of 2,048 bytes. However, tokens issued by Token Security Service can be up to 12,288 bytes. [link].

There are two types of service account JSON files:

  • Type: authorized_user. This type is created by the CLI command gcloud auth application-default login. This type is similar to OAuth Client Secrets and includes the Client ID, Client Secret, and a Refresh Token. I believe, but I have not verified, that it would be easy to create tokens with this file.
  • Type: service_account. This type is the normal service account JSON key file that you create and download from the Google Cloud Console or create with the CLI. This type includes the service account RSA private key.

Summary

The Google Cloud google/auth PHP SDK is fairly easy to use. With this SDK you can create different types of clients supporting different types of credential sources.

I have only touched the surface of this SDK. Over time, I plan to add more examples and I experiment with some of the more advanced features such as the Proxy-Authorization feature.

More Information

PHP SDK used in this article:

The examples in this article are written at a lower level than the next list of SDKs. Where possible, I try to work directly with the REST API to develop a deeper understanding of a Google Cloud service. However, using a service-based SDK, such as the Cloud Client Libraries, is generally much easier to use.

An example is the  Google Compute SDK from the Cloud Client Libraries that lists the instances in a single zone:

Those SDKs use the google/auth SDK for authentication at a lower level. For example, the InstanceClient()accepts a credentials parameter. That credential is created by the Google Auth Library FetchAuthToken() which we used in example1.php. By understanding the google/auth library, you will be able to better understand and manage authorization of the service-specific SDKs.

Google PHP SDKs – written for each API or service:

At first glance, you might assume there are hundreds of PHP SDKs. In reality, there are two major PHP SDK families. An older, more mature library that supports almost all Google APIs (Google APIs Client Library) and one that is designed for Google Cloud (Cloud Client Libraries).

One drawback of the Cloud Client Libraries is Google considers some parts to be beta quality and the SDK is missing features that require development with the REST API.

Additional information:

  • Jonathan Merlevede wrote an article ADC that is very good. His article focuses on the environment, whereas I focus on developer issues.
  • The Google Cloud Blog post that announced ADC on July 20, 2015

Photography Credits

Heidi Mustonen just started a new photography company in Seattle, WA. Her company in-TENSE Photography has some amazing pictures. I asked her for some images to include with my new articles. Check out her new website.