Skip to content

Port Gemini CLI Provider with OAuth Authentication from ClineΒ #5134

@hannesrudolph

Description

@hannesrudolph

What specific problem does this solve?

Users want free access to Google's Gemini models without needing to manage API keys or set up billing. The recently open-sourced Gemini CLI tool provides OAuth-based authentication that offers free tier access to Gemini models through Google's Code Assist API.

Who is affected: All users, especially new users, developers, and those who want to avoid API costs
When this happens: When users want to use Google Gemini models but don't have API keys set up or want to avoid API usage charges
Current behavior: Users must obtain Google API keys, configure authentication, and pay for API usage from the first request
Expected behavior: Users should be able to access Gemini models through OAuth authentication (like the Gemini CLI tool), which provides free tier access without API keys
Impact: Eliminates API key management, provides free access tier, reduces setup friction, and offers an alternative authentication method that's more secure than API keys

Additional context

This feature was recently implemented in Cline (PR #4472) and provides a sophisticated OAuth-based approach that's superior to the CLI-shelling approach that was previously considered in issue #5118.

Key Benefits:

  • Zero configuration: Works automatically after OAuth authentication
  • Cost savings: Uses the free tier through Google's Code Assist API
  • OAuth security: No need to manage API keys
  • Full model support: Supports all Gemini models available in the standard provider
  • Complete Independence: Entirely separate from existing Gemini provider - no conflicts or shared code

πŸ› οΈ Contributing & Technical Analysis

βœ… I'm interested in implementing this feature
βœ… I understand this needs approval before implementation begins

How should this be solved?

This should be implemented as a completely new and independent provider called "Gemini CLI Provider" that uses OAuth authentication with Google's authentication libraries. This is NOT a modification of the existing Gemini provider - it's an entirely separate provider with its own authentication, models, and API endpoints.

What will change:

  • Add new GeminiCliHandler provider class with OAuth2 authentication
  • Create dedicated GeminiCliProvider UI component
  • Add separate model definitions and provider registration
  • Implement Google Code Assist API integration (different from standard Gemini API)
  • Add OAuth credential management with automatic token refresh
  • Include provider-specific error handling and rate limiting

User interaction:

  • Users will see "Gemini CLI Provider" as a distinct provider option in settings dropdown
  • Completely separate from "Google Gemini" provider option
  • Setup requires authenticating with Google OAuth (opens browser)
  • OAuth credentials are stored locally and refreshed automatically
  • No API keys needed - authentication handled via OAuth flow

Acceptance Criteria

Given I want to use Gemini models without API keys
When I select "Gemini CLI Provider" in Roo Code settings  
Then I can authenticate via OAuth (browser opens for Google login)
And I can send prompts to Gemini models without API key configuration
And I receive streaming responses from the free tier
And OAuth tokens are automatically refreshed when needed
And this provider is completely independent from the existing "Google Gemini" provider
But I need to complete initial OAuth authentication setup
Given I have both Gemini and Gemini CLI providers configured
When I switch between the two providers
Then each provider uses its own authentication method and endpoints
And there are no conflicts or shared state between providers
And I can use both providers independently in different sessions
Given OAuth credentials expire or become invalid
When I try to use the Gemini CLI provider
Then the system automatically attempts to refresh the token
And on refresh failure, I receive clear instructions to re-authenticate
And failure doesn't affect the regular Gemini provider
But the extension doesn't crash or become unusable

Technical Considerations

Complete Implementation Roadmap

Phase 1: Core Infrastructure

// 1. Add new provider type to shared API types
// File: src/shared/api.ts
export type ApiProvider = 
  | "anthropic" 
  | "gemini"           // Existing provider
  | "gemini-cli"       // NEW provider - completely separate
  | // ... other providers

// Add new OAuth-specific options
export interface ApiHandlerOptions {
  // ... existing options
  geminiCliOAuthPath?: string
  geminiCliProjectId?: string
}

// Define new model set (may overlap with regular Gemini but separate definitions)
export type GeminiCliModelId = keyof typeof geminiCliModels
export const geminiCliDefaultModelId: GeminiCliModelId = "gemini-2.5-flash"
export const geminiCliModels = {
  "gemini-2.5-pro": { /* OAuth-specific model config */ },
  "gemini-2.5-flash": { /* OAuth-specific model config */ },
  // ... complete model set with OAuth-specific pricing (free tier)
}

Phase 2: Provider Implementation

// File: src/api/providers/gemini-cli.ts (ENTIRELY NEW FILE)
import { OAuth2Client } from 'google-auth-library'
import { BaseProvider } from './base-provider'

export class GeminiCliHandler extends BaseProvider {
  private authClient: OAuth2Client
  private projectId: string | null = null
  
  constructor(options: GeminiCliHandlerOptions) {
    super()
    // OAuth2 setup using Code Assist endpoints
    this.authClient = new OAuth2Client(
      OAUTH_CLIENT_ID,
      OAUTH_CLIENT_SECRET, 
      OAUTH_REDIRECT_URI
    )
  }

  // Completely different authentication flow from GeminiHandler
  private async initializeAuth(): Promise<void> { /* OAuth implementation */ }
  
  // Different API endpoints than regular Gemini
  private async callCodeAssistEndpoint(method: string, body: any): Promise<any> { 
    /* Code Assist API calls */ 
  }
  
  // Separate streaming implementation
  async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
    /* OAuth-based streaming via Code Assist API */
  }
  
  // Independent model selection
  getModel(): { id: GeminiCliModelId; info: ModelInfo } { /* OAuth model logic */ }
}

Phase 3: Provider Registration

// File: src/api/index.ts
function createHandlerForProvider(apiProvider: string | undefined, options: any) {
  switch (apiProvider) {
    case "gemini":
      return new GeminiHandler(options)           // Existing provider
    case "gemini-cli":
      return new GeminiCliHandler(options)        // NEW provider
    // ... other providers
  }
}

Phase 4: UI Components

// File: webview-ui/src/components/settings/providers/GeminiCliProvider.tsx (NEW FILE)
export const GeminiCliProvider = ({ apiConfiguration, handleInputChange, showModelOptions }: Props) => {
  return (
    <div>
      {/* OAuth-specific configuration UI */}
      <VSCodeTextField
        value={apiConfiguration?.geminiCliOAuthPath || ""}
        placeholder="Default: ~/.gemini/oauth_creds.json"
        onInput={handleInputChange("geminiCliOAuthPath")}
      >
        OAuth Credentials Path (optional)
      </VSCodeTextField>
      
      {/* OAuth setup instructions */}
      <p>This provider uses OAuth authentication and does not require API keys...</p>
      
      {/* Model selector for OAuth models */}
      {showModelOptions && (
        <ModelSelector
          models={geminiCliModels}  // Separate model set
          selectedModelId={selectedModelId}
          onChange={handleInputChange("apiModelId")}
        />
      )}
    </div>
  )
}

Phase 5: Provider UI Integration

// File: webview-ui/src/components/settings/ApiOptions.tsx
export const ApiOptions = () => {
  return (
    <div>
      <VSCodeDropdown>
        <VSCodeOption value="gemini">Google Gemini</VSCodeOption>        {/* Existing */}
        <VSCodeOption value="gemini-cli">Gemini CLI Provider</VSCodeOption> {/* NEW */}
      </VSCodeDropdown>
      
      {selectedProvider === "gemini" && <GeminiProvider {...props} />}
      {selectedProvider === "gemini-cli" && <GeminiCliProvider {...props} />}  {/* NEW */}
    </div>
  )
}

Key Architectural Differences from Existing Gemini Provider

Aspect Existing Gemini Provider New Gemini CLI Provider
Authentication API Key based OAuth2 based
API Endpoints generativelanguage.googleapis.com cloudcode-pa.googleapis.com
API Version Standard Gemini API Code Assist API (v1internal)
Cost Model Pay-per-token Free tier with rate limits
Credential Storage API key in settings OAuth tokens in ~/.gemini/oauth_creds.json
Token Management Static API key Dynamic OAuth with refresh
Project Setup None required Auto-discovery via Code Assist
Account Support Any Google account Personal Google accounts only
Rate Limiting Based on API quotas Free tier limits
Streaming Method Standard HTTP streaming Server-Sent Events

Detailed Dependency Analysis

New Dependencies Required:

{
  "dependencies": {
    "google-auth-library": "^10.1.0"  // Already present in Roo Code via Vertex provider
  }
}

No Additional Dependencies Needed: The google-auth-library package is already included in Roo Code for the Vertex provider, so no new npm dependencies are required.

Complete File Modification List

New Files to Create:

  1. src/api/providers/gemini-cli.ts - Complete OAuth handler implementation
  2. webview-ui/src/components/settings/providers/GeminiCliProvider.tsx - OAuth UI component

Existing Files to Modify:

  1. src/shared/api.ts - Add gemini-cli provider type and OAuth models
  2. src/api/index.ts - Add provider registration case
  3. webview-ui/src/components/settings/ApiOptions.tsx - Add provider dropdown option and component
  4. webview-ui/src/components/settings/utils/providerUtils.ts - Add model normalization
  5. webview-ui/src/utils/validate.ts - Add OAuth validation (if needed)
  6. Configuration conversion files for proto serialization

Testing Files to Create:

  1. src/api/providers/__tests__/gemini-cli.test.ts - Complete test suite
  2. webview-ui/src/components/settings/providers/__tests__/GeminiCliProvider.test.tsx - UI tests

OAuth Implementation Details

Authentication Flow:

// OAuth2 Configuration (from Cline implementation)
const OAUTH_CLIENT_ID = "681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com"
const OAUTH_CLIENT_SECRET = "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"
const OAUTH_REDIRECT_URI = "http://localhost:45289"

// Code Assist API Endpoints
const CODE_ASSIST_ENDPOINT = "https://cloudcode-pa.googleapis.com"
const CODE_ASSIST_API_VERSION = "v1internal"

// Key Methods:
1. loadOAuthCredentials() - Load from ~/.gemini/oauth_creds.json
2. initializeAuth() - Setup OAuth2Client with token refresh
3. discoverProjectId() - Auto-discover GCP project via Code Assist API
4. callCodeAssistEndpoint() - Make authenticated API calls
5. parseSSEStream() - Handle Server-Sent Events streaming

Project ID Discovery Process:

  1. Call loadCodeAssist endpoint with default project
  2. If no existing project, call onboardUser endpoint
  3. Poll for onboarding completion
  4. Extract discovered project ID for future requests

Error Handling & Rate Limiting

OAuth-Specific Error Handling:

  • 401 Unauthorized β†’ Automatic token refresh attempt
  • 403 Forbidden β†’ Re-authentication required
  • 429 Rate Limited β†’ Free tier limit exceeded (special UI messaging)

Rate Limit Error UI Enhancement:

// Special handling for Gemini CLI rate limits in ChatRow.tsx
if (isRateLimitError && apiConfiguration?.apiProvider === "gemini-cli") {
  return (
    <div className="rate-limit-warning">
      <p>You've hit the API rate limit. This is likely due to free tier limits.</p>
      <a href="https://codeassist.google/">Learn about tier limits</a>
    </div>
  )
}

Comprehensive Testing Strategy

Unit Tests Required:

  1. OAuth Authentication Tests

    • Token loading and validation
    • Automatic token refresh
    • Authentication failure handling
    • Project ID discovery
  2. API Integration Tests

    • Code Assist endpoint calls
    • Server-Sent Events parsing
    • Rate limit handling
    • Error response processing
  3. Provider Interface Tests

    • Model selection and validation
    • Message creation and streaming
    • Cost calculation (free tier)
    • Independence from Gemini provider
  4. UI Component Tests

    • OAuth configuration interface
    • Model selector functionality
    • Error state display
    • Authentication flow UX

Performance & Security Considerations

Performance Optimizations:

  • OAuth token caching and reuse
  • Automatic background token refresh
  • Efficient SSE stream parsing
  • Connection pooling for API calls

Security Measures:

  • Secure OAuth credential storage
  • Token expiration handling
  • HTTPS-only API communication
  • Input validation and sanitization

Compatibility Safeguards:

  • No shared state with existing Gemini provider
  • Independent configuration storage
  • Separate error handling paths
  • Isolated model definitions

Trade-offs and Risks

Alternatives considered:

  • Modify existing Gemini provider: Rejected to avoid complexity and maintain clean separation
  • CLI shelling approach (issue Add Gemini CLI provider supportΒ #5118): Rejected in favor of direct OAuth integration
  • Unified OAuth/API key provider: Decided against to keep authentication methods clear and separate

Potential risks:

  • OAuth complexity: Mitigated by using proven google-auth-library and Cline's implementation as reference
  • Code duplication: Some overlap with Gemini provider, but necessary for independence
  • Free tier limits: Clear error messaging and rate limit handling implemented
  • Google API changes: Risk exists but Code Assist API is actively maintained by Google

Breaking changes:

  • None: Completely additive feature with no impact on existing functionality
  • Provider independence: Existing Gemini provider continues to work unchanged
  • Configuration isolation: No conflicts between OAuth and API key authentication

Metadata

Metadata

Assignees

Labels

Issue - In ProgressSomeone is actively working on this. Should link to a PR soon.enhancementNew feature or requestproposal

Type

No type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions