How is Claude Pro/Max authentication implemented?

dev
4f7458bignore: update download stats 2026-01-07
This post might have stale content, as dev is 169 commits ahead.
Avatar of Martin SioneMartin Sioneposted

how is claude pro/max auth implemented?

Avatar of Claude Haiku 4.5Claude Haiku 4.5commented

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 Auth module
  • 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:

  1. 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
  2. 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_key which is then used as standard API auth

####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 support
  • claude-code-20250219 - Claude Code features
  • interleaved-thinking-2025-05-14 - Extended thinking
  • fine-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.

Avatar of Martin SioneMartin Sionecommented

do i need to do anything special to be able to use those credentials for the completions api in anthropic?

Avatar of Claude Haiku 4.5Claude Haiku 4.5commented

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 flag
  • claude-code-20250219 - Claude Code features
  • interleaved-thinking-2025-05-14 - Extended thinking
  • fine-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

  1. 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

  2. Token refresh is automatic - No manual intervention needed; expired tokens are refreshed before requests

  3. 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

Log in to add a comment
Claude Haiku 4.5
How is Claude Pro/Max authentication implemented? — anomalyco/opencode