Provider Authentication Flow in Forge: OAuth Methods and Configuration Guide

The provider authentication flow in Forge is orchestrated by ForgeProviderAuthService through three phases—Initialize, Complete, and Refresh—supporting API keys, Google Application Default Credentials (ADC), OAuth device code, OAuth authorization code, and Codex-specific device flows.

The antinomyhq/forgecode repository implements a pluggable, strategy-based authentication system that abstracts provider-specific OAuth complexities into a unified interface. This architecture allows each provider to declare supported authentication methods while the service coordinates credential lifecycle management.

How the Provider Authentication Flow Works

ForgeProviderAuthService implements the ProviderAuthService trait defined in crates/forge_services/src/provider_auth.rs. The service drives three distinct phases:

  1. Initialize – Prepare an auth request (device code, auth-code URL, or API-key prompt).
  2. Complete – Consume the user response, resolve the concrete AuthMethod, execute the strategy, and persist the credential.
  3. Refresh – Proactively renew expiring OAuth tokens or Google ADC credentials without user interaction.

Each phase delegates to concrete strategies (e.g., OAuthDeviceStrategy, OAuthCodeStrategy, GoogleAdcStrategy, or ApiKeyStrategy) created via the infrastructure factory.

Phase 1: Initialize Authentication (init_provider_auth)

The initialization phase begins with init_provider_auth, defined at lines 27–74 in crates/forge_services/src/provider_auth.rs:

async fn init_provider_auth(
    &self,
    provider_id: ProviderId,
    auth_method: AuthMethod,
) -> anyhow::Result<AuthContextRequest>

Collecting URL Parameters

For API key and Google ADC flows, the system first collects url_params() from the provider configuration (host, region, etc.):

let required_params = if matches!(auth_method, AuthMethod::ApiKey | AuthMethod::GoogleAdc) {
    // fetch the provider entry and clone its URL parameters
} else { vec![] };

Strategy Creation and Execution

The service instantiates the appropriate strategy via the infrastructure factory:

let strategy = self.infra.create_auth_strategy(
    provider_id.clone(),
    auth_method.clone(),
    required_params,
)?;
let request = strategy.init().await?;

The init() call returns an AuthContextRequest containing provider-specific payloads (device codes, authorization URLs, or API-key field definitions).

Credential Prefilling

If existing credentials are stored for API-key or ADC flows, the service prefills these values (lines 55–71), enabling seamless provider switching without re-entering static keys.

Phase 2: Complete Authentication (complete_provider_auth)

The completion phase resolves user responses into concrete credentials via complete_provider_auth (lines 77–133):

async fn complete_provider_auth(
    &self,
    provider_id: ProviderId,
    auth_context_response: AuthContextResponse,
    _timeout: Duration,
) -> anyhow::Result<()>

AuthMethod Detection

The service inspects AuthContextResponse to determine the concrete authentication type:

  • AuthContextResponse::ApiKey – Maps to ApiKey or GoogleAdc (detected via the special "google_adc_marker" string for Vertex AI providers).
  • AuthContextResponse::Code – Maps to OAuthCode with the supplied OAuthConfig.
  • AuthContextResponse::DeviceCode – Maps to OAuthDevice or CodexDevice if the provider is CODEX.

Strategy Completion and Persistence

After resolving the method, the service gathers URL parameters if needed, executes strategy.complete(auth_context_response).await to perform token exchange or API key validation, then persists the resulting credential via upsert_credential (line 132).

Phase 3: Refresh Credentials (refresh_provider_credential)

Long-running sessions remain valid through automatic credential renewal (lines 138–200). The service iterates through each provider's auth_methods, identifying refreshable types (OAuthDevice, OAuthCode, CodexDevice, GoogleAdc). For each:

  1. Retrieves the existing credential from storage.
  2. Creates the associated strategy via the factory.
  3. Executes strategy.refresh(&existing_credential).
  4. Persists the refreshed token if successful.

Supported OAuth Configurations

All OAuth-capable methods carry an OAuthConfig structure defined in crates/forge_domain/src/auth/oauth_config.rs (lines 12–28). The configuration fields include:

Field Purpose
auth_url Authorization endpoint (e.g., https://auth.openai.com/api/accounts/deviceauth/usercode).
token_url Token exchange endpoint (e.g., https://auth.openai.com/oauth/token).
client_id Application identifier (ClientId).
scopes Requested OAuth scopes (e.g., ["openid"]).
redirect_uri Optional callback URL for authorization-code flows.
use_pkce Boolean flag enabling PKCE (RFC 7636) for enhanced security.
token_refresh_url Optional separate endpoint for refresh token exchange.
custom_headers Additional HTTP headers (e.g., User-Agent).
extra_auth_params Custom query parameters appended to authorization requests.

AuthMethod Variants

The AuthMethod enum in crates/forge_domain/src/auth/auth_method.rs defines supported mechanisms:

  • OAuthDevice(OAuthConfig) – Device-code flow where users manually enter codes at verification URLs.
  • OAuthCode(OAuthConfig) – Standard authorization-code flow with browser redirects.
  • CodexDevice(OAuthConfig) – Codex-specific device-code implementation.
  • GoogleAdc – Google Application Default Credentials (metadata server or local ADC files).
  • ApiKey – Simple header-based authentication without OAuth negotiation.

Code Examples

Initializing an Authentication Flow

use forge_domain::{AuthMethod, ProviderId};
use forge_services::ProviderAuthService;

let provider_id = ProviderId::VERTEX_AI;
let oauth_cfg = OAuthConfig {
    auth_url: "https://auth.example.com/device".to_string(),
    token_url: "https://auth.example.com/token".to_string(),
    client_id: "forge-client".to_string(),
    scopes: vec!["openid".to_string()],
    use_pkce: true,
    ..Default::default()
};
let method = AuthMethod::oauth_device(oauth_cfg);

let request = services
    .provider_auth_service()
    .init_provider_auth(provider_id, method)
    .await?;
// `request` contains device-code payload for UI display

Completing the Flow

use forge_domain::AuthContextResponse;
use std::time::Duration;

let response = AuthContextResponse::DeviceCode(DeviceCodeResponse {
    device_code: "user-entered-code".to_string(),
    verification_url: "https://verify.example.com".to_string(),
    // ... other fields
});

services
    .provider_auth_service()
    .complete_provider_auth(
        provider_id, 
        response, 
        Duration::from_secs(30)
    )
    .await?;

Refreshing Credentials Programmatically

let provider = provider_repo.get(provider_id).await?;
let refreshed = services
    .provider_auth_service()
    .refresh_provider_credential(provider)
    .await?;

Key Source Files

Summary

  • The provider authentication flow in Forge follows a three-phase lifecycle: Initialize, Complete, and Refresh.
  • ForgeProviderAuthService in provider_auth.rs coordinates generic authentication through strategy delegation.
  • Supported methods include OAuth device code, OAuth authorization code, Google ADC, Codex device flows, and API keys.
  • OAuthConfig provides granular control over endpoints, scopes, PKCE, and custom headers.
  • Automatic credential refresh ensures long-running sessions remain valid without manual re-authentication.

Frequently Asked Questions

What authentication methods does Forge support for AI providers?

Forge supports five distinct authentication methods defined in the AuthMethod enum: ApiKey for header-based authentication, OAuthDevice for device-code flows, OAuthCode for authorization-code redirects, GoogleAdc for Google Application Default Credentials, and CodexDevice for Codex-specific device authentication. Each method is implemented as a discrete strategy in the forge_infra crate.

How does Forge handle OAuth token expiration?

The refresh_provider_credential method (lines 138–200 in provider_auth.rs) proactively renews tokens by iterating through refreshable auth methods, retrieving stored credentials, and invoking strategy.refresh(&existing_credential) for OAuthDevice, OAuthCode, CodexDevice, and GoogleAdc flows. Refreshed tokens are automatically persisted to the credential repository.

What is the difference between OAuthDevice and OAuthCode in Forge?

OAuthDevice implements the device authorization grant (RFC 8628) where users manually enter codes at verification URLs, suitable for CLI environments without browser access. OAuthCode implements the standard authorization-code flow with browser redirects, requiring a redirect_uri in the OAuthConfig. Both use the same configuration structure but employ distinct strategy implementations in crates/forge_infra/src/auth/strategy.rs.

Can providers use custom OAuth parameters like PKCE?

Yes. The OAuthConfig struct includes a use_pkce boolean field to enable PKCE (RFC 7636) for public clients, along with custom_headers and extra_auth_params fields for provider-specific requirements. These are passed through the strategy factory when constructing OAuthDeviceStrategy or OAuthCodeStrategy instances.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →