How is Claude Pro/Max authentication implemented?
how is claude pro/max auth implemented?
I'll help you find how Claude Pro/Max auth is implemented in this repository. Let me start by exploring the codebase structure.
Now let me search for files related to Claude Pro/Max auth:
Let me search more specifically for authentication implementation files:
Now let me examine the auth-related files:
Now let me look at the provider-specific implementation and how Claude Pro/Max auth is handled:
Let me check how the plugin system handles auth for Anthropic:
Perfect! Now let me look at the actual Anthropic auth plugin:
Perfect! Now let me get the source from the opencode-anthropic-auth repository:
Let me get the actual source code of the main index file:
Perfect! Now I have all the information I need. Let me provide a comprehensive answer about how Claude Pro/Max authentication is implemented.
##Claude Pro/Max Authentication Implementation
Based on the source code, here's how Claude Pro/Max auth is implemented in OpenCode:
###Architecture Overview
Claude Pro/Max authentication is implemented as a plugin system (opencode-anthropic-auth), which is loaded as a built-in component. The system uses a modular, layered approach:
###1. Plugin System (packages/opencode/src/plugin/index.ts)
OpenCode loads the Anthropic auth plugin as a built-in component:
const BUILTIN = ["opencode-copilot-auth@0.0.9", "opencode-anthropic-auth@0.0.5"]
Plugins are dynamically loaded and registered, providing hooks for authentication across the system.
###2. Authentication Storage (packages/opencode/src/auth/index.ts)
Credentials are stored locally in ~/.opencode/data/auth.json with secure file permissions (chmod 0o600). Three auth types are supported:
// OAuth tokens with refresh capability
export const Oauth = z.object({
type: z.literal("oauth"),
refresh: z.string(),
access: z.string(),
expires: z.number(),
enterpriseUrl: z.string().optional(),
})
// Direct API keys
export const Api = z.object({
type: z.literal("api"),
key: z.string(),
})
// WellKnown auth (enterprise)
export const WellKnown = z.object({
type: z.literal("wellknown"),
key: z.string(),
token: z.string(),
})
###3. Provider Auth Handler (packages/opencode/src/provider/auth.ts)
The ProviderAuth namespace manages OAuth flows:
- Calls plugin auth methods via the
authorize()function - Handles OAuth callbacks and token exchange
- Stores credentials using the
Authmodule - Supports both OAuth and API key methods
###4. Anthropic OAuth Plugin (opencode-anthropic-auth)
The core authentication logic uses OAuth with PKCE (Proof Key for Code Exchange):
####Key Features:
Two Auth Methods:
-
Claude Pro/Max OAuth - Direct login via Anthropic:
- Uses Claude.ai OAuth endpoint (
https://claude.ai/oauth/authorize) - Redirects to
https://console.anthropic.com/oauth/code/callback - Scopes:
org:create_api_key user:profile user:inference - Uses PKCE for security
- Uses Claude.ai OAuth endpoint (
-
Create API Key via Console - For API key generation:
- Uses Anthropic Console OAuth (
https://console.anthropic.com/oauth/authorize) - Automatically creates an API key via:
https://api.anthropic.com/api/oauth/claude_cli/create_api_key - Returns
raw_keywhich is then used as standard API auth
- Uses Anthropic Console OAuth (
####OAuth Flow:
// 1. Authorization URL generation with PKCE
async function authorize(mode) {
const pkce = await generatePKCE()
const url = new URL(
`https://${mode === "console" ? "console.anthropic.com" : "claude.ai"}/oauth/authorize`
)
url.searchParams.set("client_id", CLIENT_ID) // 9d1c250a-e61b-44d9-88ed-5944d1962f5e
url.searchParams.set("code_challenge", pkce.challenge)
url.searchParams.set("code_challenge_method", "S256")
// ... other params
return { url, verifier }
}
// 2. Token Exchange
async function exchange(code, verifier) {
const result = await fetch("https://console.anthropic.com/v1/oauth/token", {
method: "POST",
body: JSON.stringify({
code,
grant_type: "authorization_code",
client_id: CLIENT_ID,
code_verifier: verifier,
}),
})
return {
type: "success",
refresh: json.refresh_token,
access: json.access_token,
expires: Date.now() + json.expires_in * 1000,
}
}
####Token Refresh:
When tokens expire, the system automatically refreshes:
if (!auth.access || auth.expires < Date.now()) {
const response = await fetch("https://console.anthropic.com/v1/oauth/token", {
method: "POST",
body: JSON.stringify({
grant_type: "refresh_token",
refresh_token: auth.refresh,
client_id: CLIENT_ID,
}),
})
// Store updated tokens
}
###5. Cost Zeroing for Pro/Max
When OAuth auth is detected, model costs are zeroed out (indicating a paid subscription plan with unlimited usage):
if (auth.type === "oauth") {
// zero out cost for max plan
for (const model of Object.values(provider.models)) {
model.cost = {
input: 0,
output: 0,
cache: { read: 0, write: 0 },
}
}
}
###6. Request Interception
The plugin intercepts all API requests to add OAuth tokens and beta headers:
async fetch(input, init) {
const auth = await getAuth()
// Inject Bearer token
const headers = {
...init.headers,
authorization: `Bearer ${auth.access}`,
"anthropic-beta": mergedBetas, // OAuth beta + other feature betas
}
return fetch(input, { ...init, headers })
}
###7. Beta Headers
For Claude Pro/Max, additional beta features are enabled:
oauth-2025-04-20- OAuth supportclaude-code-20250219- Claude Code featuresinterleaved-thinking-2025-05-14- Extended thinkingfine-grained-tool-streaming-2025-05-14- Streaming support
###Authentication Flow Summary
User selects "Claude Pro/Max"
↓
authorize("max") generates PKCE-protected URL
↓
User logs into https://claude.ai/oauth/authorize
↓
Redirects to callback with authorization code
↓
exchange(code, verifier) exchanges code for tokens
↓
OAuth tokens stored in ~/.opencode/data/auth.json
↓
On API calls: tokens auto-refresh if expired
↓
Bearer token + beta headers injected into requests
This design provides a secure, user-friendly OAuth flow that supports both Claude Pro/Max subscriptions and API key-based authentication, with automatic token management and feature enablement.
do i need to do anything special to be able to use those credentials for the completions api in anthropic?
Let me check the Anthropic API documentation and how OpenCode uses the credentials for the completions API.
Let me look at the Anthropic SDK integration more specifically:
Now let me check how the credentials are passed to the SDK:
Let me check how credentials are passed when initializing the provider:
Perfect! Now let me look at how the SDK is actually initialized with the options:
Excellent! Now I have all the information. Let me provide a comprehensive answer.
##Using OAuth Credentials with Anthropic's Completions API
Based on the source code and Anthropic API documentation, here's what you need to know about using Claude Pro/Max OAuth credentials with the Anthropic completions API:
###Yes, OAuth credentials work directly with the Completions API
The OpenCode anthropic-auth plugin intercepts all API requests and automatically injects the OAuth Bearer token. Here's how:
###The Request Interception System
When you have OAuth credentials configured, the plugin wraps the fetch function and adds the Bearer token to every request:
async fetch(input, init) {
const auth = await getAuth()
if (auth.type !== "oauth") return fetch(input, init)
// Auto-refresh token if expired
if (!auth.access || auth.expires < Date.now()) {
const response = await fetch("https://console.anthropic.com/v1/oauth/token", {
method: "POST",
body: JSON.stringify({
grant_type: "refresh_token",
refresh_token: auth.refresh,
client_id: CLIENT_ID,
}),
})
// Update stored tokens
await client.auth.set({ ... })
}
// Inject Bearer token into Authorization header
const headers = {
...init.headers,
authorization: `Bearer ${auth.access}`,
"anthropic-beta": mergedBetas, // Include feature betas
}
return fetch(input, { ...init, headers })
}
###Key Implementation Details
1. Token Format The OAuth access token is used directly as a Bearer token:
Authorization: Bearer sk-ant-oat01-xxxxx...
2. Automatic Token Refresh
- Tokens are checked before each request
- If expired (
auth.expires < Date.now()), automatic refresh happens - Refreshed tokens are stored back to disk
3. Beta Headers Enabled OAuth requests automatically get these Anthropic beta headers:
oauth-2025-04-20- OAuth support flagclaude-code-20250219- Claude Code featuresinterleaved-thinking-2025-05-14- Extended thinkingfine-grained-tool-streaming-2025-05-14- Tool streaming
###Usage in Code
When you use OpenCode with OAuth credentials, the AI SDK is initialized with:
// Credentials are loaded from Auth storage
const auth = await Auth.get("anthropic")
if (auth?.type === "oauth") {
// SDK is created with custom fetch handler
const sdk = createAnthropic({
name: "anthropic",
fetch: async (input, init) => {
// Bearer token automatically injected here
return fetch(input, {
...init,
headers: {
authorization: `Bearer ${auth.access}`,
...init.headers
}
})
}
})
}
###No Special Setup Required
You don't need to do anything special. The system automatically:
✅ Uses OAuth tokens for all requests
✅ Refreshes expired tokens transparently
✅ Strips x-api-key header if using OAuth
✅ Adds required beta headers
✅ Zeros out model costs (indicating unlimited subscription)
###Important Notes
-
The Anthropic SDK handles this for you - Since OpenCode uses
@ai-sdk/anthropic, the SDK wrapper applies the fetch function to all completions API calls -
Token refresh is automatic - No manual intervention needed; expired tokens are refreshed before requests
-
Works with all endpoints - The Bearer token approach works with:
/v1/messages(Messages API)- Streaming endpoints
- Batch processing
- All other Anthropic endpoints that support OAuth
###Why This Works
Anthropic's OAuth flow was designed to work directly with their API. The token you receive from the OAuth flow is exactly what their completions API expects - a Bearer token in the Authorization header. OpenCode just manages the storage, refresh, and injection of this token automatically.
So in summary: Just authenticate once with "Claude Pro/Max" in OpenCode, and the OAuth credentials are used automatically for all completions API calls without any additional configuration needed.
END OF POST
Claude Haiku 4.5