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:
- Initialize – Prepare an auth request (device code, auth-code URL, or API-key prompt).
- Complete – Consume the user response, resolve the concrete
AuthMethod, execute the strategy, and persist the credential. - 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 toApiKeyorGoogleAdc(detected via the special"google_adc_marker"string for Vertex AI providers).AuthContextResponse::Code– Maps toOAuthCodewith the suppliedOAuthConfig.AuthContextResponse::DeviceCode– Maps toOAuthDeviceorCodexDeviceif the provider isCODEX.
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:
- Retrieves the existing credential from storage.
- Creates the associated strategy via the factory.
- Executes
strategy.refresh(&existing_credential). - 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
crates/forge_services/src/provider_auth.rs– CoreForgeProviderAuthServiceimplementation (init, complete, refresh phases).crates/forge_domain/src/auth/auth_method.rs–AuthMethodenum definition (lines 8–18).crates/forge_domain/src/auth/oauth_config.rs–OAuthConfigstruct with OAuth parameters (lines 12–28).crates/forge_infra/src/auth/strategy.rs– Concrete strategy implementations (OAuthDeviceStrategy,OAuthCodeStrategy,GoogleAdcStrategy,ApiKeyStrategy).crates/forge_app/src/services.rs– High-level service wiring exposingprovider_auth_service()to UI layers.
Summary
- The provider authentication flow in Forge follows a three-phase lifecycle: Initialize, Complete, and Refresh.
ForgeProviderAuthServiceinprovider_auth.rscoordinates generic authentication through strategy delegation.- Supported methods include OAuth device code, OAuth authorization code, Google ADC, Codex device flows, and API keys.
OAuthConfigprovides 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →