Skip to main content

OpenRouter OAuth Integration

Overview

OpenRouter is now fully integrated as a provider in Vibe Browser with OAuth authentication support. Unlike OpenAI (which doesn't offer public OAuth), OpenRouter provides a simple OAuth PKCE flow that actually works.

Why OpenRouter OAuth Works

FeatureOpenAIOpenRouter
Public OAuth❌ NoYes
Client ID RequiredN/A❌ No
Pre-registrationN/A❌ No
Works Now

How It Works

User Flow

  1. User selects an OpenRouter model (e.g., openrouter:anthropic/claude-3.5-sonnet)
  2. If no API key is set, a "Quick Connect" button appears
  3. User clicks "Connect"
  4. Redirected to OpenRouter login page
  5. User authorizes Vibe Browser
  6. Returns with permanent API key
  7. API key stored securely in Chrome storage

Technical Flow

┌─────────────┐
│ User │
└──────┬──────┘
│ 1. Select openrouter:* model

┌─────────────────┐
│ Settings Page │ (OAuth button appears)
└──────┬──────────┘
│ 2. Click "Connect"

┌─────────────────┐
│ OAuth Service │ Generate PKCE challenge
└──────┬──────────┘
│ 3. Redirect to OpenRouter

┌──────────────────────────────────────┐
│ https://openrouter.ai/auth? │
│ callback_url=chrome-extension:// │
│ code_challenge=xxx │
│ code_challenge_method=S256 │
│ state=random-uuid │
└──────┬───────────────────────────────┘
│ 4. User logs in & approves

┌─────────────────┐
│ Callback │ Returns with code
└──────┬──────────┘
│ 5. Exchange code for API key

┌─────────────────────────────────────┐
│ POST /api/v1/auth/keys │
│ { code, code_verifier } │
└──────┬──────────────────────────────┘
│ 6. Returns: { key: "sk-or-v1-xxx" }

┌─────────────────┐
│ Token Manager │ Store API key
└─────────────────┘

Implementation Details

OAuth Configuration

// apps/chat4/src/services/oauth.ts
openrouter: {
clientId: 'NOT_REQUIRED',
authUrl: 'https://openrouter.ai/auth',
tokenUrl: 'https://openrouter.ai/api/v1/auth/keys',
scopes: [],
usesPKCE: true
}

Authorization Request

GET https://openrouter.ai/auth?
callback_url=https://<EXTENSION_ID>.chromiumapp.org/
&code_challenge=<BASE64_SHA256_HASH>
&code_challenge_method=S256
&state=<RANDOM_UUID>

Key Differences from Standard OAuth:

  • Uses callback_url instead of redirect_uri
  • No client_id parameter
  • No response_type parameter
  • No scope parameter

Token Exchange

POST https://openrouter.ai/api/v1/auth/keys
Content-Type: application/json

{
"code": "auth_code_from_callback",
"code_verifier": "random_string_from_pkce"
}

Response:

{
"key": "sk-or-v1-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}

Key Differences:

  • Returns actual API key (not access_token)
  • No refresh_token (keys don't expire)
  • No expires_in (keys are permanent)
  • Uses JSON POST (not form-urlencoded)

Provider Configuration

Already configured in:

  • apps/chat4/src/constants/providers.ts - Provider info
  • lib/utils/initChatModel.js - Uses ChatOpenAI with custom baseURL
  • apps/chat4/src/constants/models.ts - Popular OpenRouter models

Base URL:

https://openrouter.ai/api/v1

OpenRouter is OpenAI-compatible, so it uses the same ChatOpenAI class from LangChain.

Available Models

OpenRouter provides access to models from multiple providers:

// Anthropic via OpenRouter
'openrouter:anthropic/claude-3.5-sonnet'
'openrouter:anthropic/claude-3-opus'
'openrouter:anthropic/claude-3-haiku'

// Google via OpenRouter
'openrouter:google/gemini-2.5-flash-preview-09-2025'
'openrouter:google/gemini-2.0-flash-exp:free'

// Meta via OpenRouter
'openrouter:meta-llama/llama-3.3-70b-instruct'
'openrouter:meta-llama/llama-3.1-405b-instruct'

// DeepSeek via OpenRouter
'openrouter:deepseek/deepseek-chat'
'openrouter:deepseek/deepseek-r1'

// xAI via OpenRouter
'openrouter:x-ai/grok-4-fast'
'openrouter:x-ai/grok-2'

// And many more...

User Benefits

With OAuth:

  • One-click authentication
  • No copy/paste of API keys
  • Automatic account linking
  • User controls spending in OpenRouter dashboard
  • Can revoke access anytime

Without OAuth (Manual API Key):

Testing

1. Build Extension

npm run build:extension

2. Test OAuth Flow

  1. Load extension in Chrome
  2. Go to settings
  3. Select model: openrouter:anthropic/claude-3.5-sonnet
  4. "Quick Connect" button should appear
  5. Click "Connect"
  6. Should redirect to OpenRouter login
  7. Log in with OpenRouter account
  8. Approve access
  9. Should return to Vibe with API key set

3. Verify API Key

Check in Chrome DevTools:

chrome.storage.local.get('vibe_oauth_token_openrouter', (result) => {
console.log(result);
});

Should show:

{
"vibe_oauth_token_openrouter": "{\"access_token\":\"sk-or-v1-xxx\",\"provider\":\"openrouter\",\"created_at\":1234567890}"
}

4. Test API Call

Try running a query with the OpenRouter model. Should work without manual API key.

Troubleshooting

OAuth button doesn't appear

  • Ensure you selected an openrouter:* model
  • Ensure no API key is already set
  • Check browser console for errors

Redirect fails

  • Verify extension ID matches callback URL
  • Check Chrome Identity API is available
  • Look for errors in service worker console

Token exchange fails

  • Check network tab for API response
  • Verify PKCE challenge/verifier match
  • Ensure code hasn't expired (use quickly)

API calls fail with OAuth key

  • Verify key starts with sk-or-v1-
  • Check OpenRouter dashboard for usage/limits
  • Try manual API key to isolate OAuth vs API issue

Security

PKCE Protection

  • Code verifier: 32 random bytes, base64url encoded
  • Code challenge: SHA-256 hash of verifier
  • Prevents authorization code interception attacks

Storage

  • API key stored in chrome.storage.local
  • Chrome provides encryption at rest
  • Only accessible by extension

No Client Secret

  • OpenRouter doesn't use client secrets (public client)
  • PKCE replaces client secret for security
  • Safe for browser extensions

Comparison with Manual API Keys

AspectOAuthManual API Key
SetupOne clickCopy/paste
SecurityPKCE protectedUser responsibility
RevocationVia OpenRouter dashboardDelete key
User ExperienceBestGood
ReliabilitySame API key formatSame API key format
ExpirationNeverNever

Future Enhancements

  • Show account info (email, credits) after OAuth
  • Allow switching between multiple OpenRouter accounts
  • Show usage statistics from OpenRouter API
  • Add OAuth for other providers if they support it
  • Implement token revocation on disconnect

References