How is Claude Pro/Max authentication implemented?
how is claude pro/max auth implemented?
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?
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