Application Default Credentials (ADC) for Google Cloud authentication.
This module implements Google's Application Default Credentials (ADC) strategy, which provides a standardized way to obtain credentials for Google Cloud APIs without hardcoding authentication details in your application.
ADC Credential Search Order
gemini_ex searches for credentials in the following order:
- Environment Variable (JSON, gemini_ex extension):
GOOGLE_APPLICATION_CREDENTIALS_JSONcontaining the service account JSON content directly (useful for containerized environments) - Environment Variable (Path, standard ADC):
GOOGLE_APPLICATION_CREDENTIALSpointing to a service account JSON file - User Credentials (standard ADC):
~/.config/gcloud/application_default_credentials.json(created viagcloud auth application-default login) - GCP Metadata Server (standard ADC): Automatic credentials for code running on GCP infrastructure (Compute Engine, GKE, Cloud Run, Cloud Functions, App Engine)
Features
- Automatic credential discovery following ADC conventions
- Token caching with automatic refresh
- Support for service account and user credentials
- Metadata server authentication for GCP workloads
- Thread-safe token management
Usage
# Load credentials using ADC
case ADC.load_credentials() do
{:ok, credentials} ->
# Get an access token
case ADC.get_access_token(credentials) do
{:ok, token} ->
# Use token for API calls
make_api_call(token)
{:error, reason} ->
Logger.error("Failed to get token: #{reason}")
end
{:error, reason} ->
Logger.error("No credentials found: #{reason}")
endSetting Up ADC
Option 1: Service Account JSON Content (Containerized Environments)
export GOOGLE_APPLICATION_CREDENTIALS_JSON='{"type":"service_account",...}'Option 2: Service Account Key File (Development)
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account-key.json"Option 3: User Credentials (Development)
gcloud auth application-default loginOption 4: Metadata Server (Production on GCP)
# No setup required - automatically works on GCP infrastructureToken Caching
Access tokens are automatically cached with a 5-minute refresh buffer. This means a token with a 1-hour TTL will be refreshed after 55 minutes, ensuring your application never uses an expired token.
Summary
Functions
Check if ADC credentials are available.
Get an access token from loaded credentials.
Get project ID from credentials if available.
Load credentials following the ADC chain.
Refresh an access token.
Types
@type access_token() :: String.t()
@type credentials() :: {:service_account, service_account_credentials()} | {:user, user_credentials()} | {:metadata_server, metadata_server_credentials()}
@type error_reason() :: String.t()
@type metadata_server_credentials() :: %{ source: :metadata_server, project_id: String.t() | nil }
@type service_account_credentials() :: %{ type: String.t(), project_id: String.t(), private_key_id: String.t(), private_key: String.t(), client_email: String.t(), client_id: String.t(), auth_uri: String.t(), token_uri: String.t(), auth_provider_x509_cert_url: String.t(), client_x509_cert_url: String.t() }
Functions
@spec available?() :: boolean()
Check if ADC credentials are available.
Performs a quick check to see if any credentials can be found via ADC, without actually loading them.
Returns
true- Credentials are availablefalse- No credentials found
Examples
if ADC.available?() do
Logger.info("ADC credentials available")
else
Logger.warning("No ADC credentials found")
end
@spec get_access_token( credentials(), keyword() ) :: {:ok, access_token()} | {:error, error_reason()}
Get an access token from loaded credentials.
Attempts to retrieve a cached token first. If no cached token exists or the cached token is expired, generates a new token and caches it.
Parameters
credentials: Credentials tuple fromload_credentials/0opts: Optional keyword list:force_refresh- Skip cache and force token refresh (default: false):cache_key- Custom cache key (default: auto-generated)
Returns
{:ok, access_token}- Access token retrieved successfully{:error, reason}- Failed to get access token
Examples
{:ok, creds} = ADC.load_credentials()
# Get token (uses cache if available)
{:ok, token} = ADC.get_access_token(creds)
# Force refresh
{:ok, fresh_token} = ADC.get_access_token(creds, force_refresh: true)
@spec get_project_id(credentials()) :: {:ok, String.t()} | {:error, error_reason()}
Get project ID from credentials if available.
Extracts the project ID from the loaded credentials. Useful for configuring Vertex AI which requires a project ID.
Parameters
credentials: Credentials tuple fromload_credentials/0
Returns
{:ok, project_id}- Project ID extracted successfully{:error, reason}- No project ID available in credentials
Examples
{:ok, creds} = ADC.load_credentials()
case ADC.get_project_id(creds) do
{:ok, project_id} ->
# Use for Vertex AI
%{project_id: project_id, location: "us-central1"}
{:error, _} ->
# Prompt user or use environment variable
System.get_env("VERTEX_PROJECT_ID")
end
@spec load_credentials() :: {:ok, credentials()} | {:error, error_reason()}
Load credentials following the ADC chain.
Searches for credentials in this order:
- GOOGLE_APPLICATION_CREDENTIALS_JSON environment variable (JSON content, gemini_ex extension)
- GOOGLE_APPLICATION_CREDENTIALS environment variable (file path, standard ADC)
- User credentials file (~/.config/gcloud/application_default_credentials.json, standard ADC)
- GCP metadata server (standard ADC)
Returns
{:ok, credentials}- Credentials found and loaded{:error, reason}- No credentials found or loading failed
Examples
case ADC.load_credentials() do
{:ok, {:service_account, creds}} ->
Logger.info("Using service account: #{creds.client_email}")
{:ok, {:user, creds}} ->
Logger.info("Using user credentials")
{:ok, {:metadata_server, creds}} ->
Logger.info("Using metadata server")
{:error, reason} ->
Logger.error("No credentials found: #{reason}")
end
@spec refresh_token(credentials()) :: {:ok, access_token()} | {:error, error_reason()}
Refresh an access token.
Forces a token refresh regardless of whether a cached token exists.
This is equivalent to calling get_access_token/2 with force_refresh: true.
Parameters
credentials: Credentials tuple fromload_credentials/0
Returns
{:ok, access_token}- New access token generated successfully{:error, reason}- Failed to refresh token
Examples
{:ok, creds} = ADC.load_credentials()
{:ok, fresh_token} = ADC.refresh_token(creds)