# OAuth Flow

How OAuth authentication works with Anthropic's Claude subscription.

## Overview

We use OAuth 2.0 with PKCE (Proof Key for Code Exchange) to authenticate with your Claude Pro/Max subscription. This allows you to use your existing subscription instead of paying for API credits.

## Why PKCE?

PKCE prevents authorization code interception attacks. It works like this:

1. Generate a random secret (`verifier`)
2. Hash it (`challenge`)
3. Send the hash during authorization
4. Prove you know the secret during token exchange

Even if someone intercepts the authorization code, they can't exchange it without the verifier.

## The Flow

### Step 1: Generate PKCE

```rust
let pkce = Pkce::generate();
// pkce.verifier  = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
// pkce.challenge = "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"
```

### Step 2: Build Authorization URL

```
https://claude.ai/oauth/authorize?
  client_id=9d1c250a-e61b-44d9-88ed-5944d1962f5e
  &response_type=code
  &redirect_uri=https://console.anthropic.com/oauth/code/callback
  &scope=org:create_api_key user:profile user:inference
  &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
  &code_challenge_method=S256
  &state=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
```

Note: We put the `verifier` in the `state` parameter for convenience.

### Step 3: User Authorizes

User visits the URL, logs into Claude, and authorizes the application.

### Step 4: Get Authorization Code

After authorization, the user receives a code like:

```
abc123xyz#dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
      │                        │
      │                        └── state (our verifier)
      └── authorization code
```

### Step 5: Exchange Code for Tokens

```
POST https://console.anthropic.com/v1/oauth/token
Content-Type: application/json

{
  "grant_type": "authorization_code",
  "code": "abc123xyz",
  "client_id": "9d1c250a-e61b-44d9-88ed-5944d1962f5e",
  "redirect_uri": "https://console.anthropic.com/oauth/code/callback",
  "code_verifier": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk",
  "state": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
}
```

Response:

```json
{
  "access_token": "sk-ant-oat-...",
  "refresh_token": "sk-ant-ort-...",
  "expires_in": 3600
}
```

### Step 6: Use Access Token

```
POST https://api.anthropic.com/v1/messages?beta=true
Authorization: Bearer sk-ant-oat-...
User-Agent: claude-cli/2.1.2 (external, cli)
anthropic-beta: oauth-2025-04-20,interleaved-thinking-2025-05-14
anthropic-version: 2023-06-01
Content-Type: application/json

{
  "model": "claude-sonnet-4-20250514",
  "max_tokens": 1024,
  "system": "You are Claude Code, Anthropic's official CLI for Claude.",
  "tools": [],
  "messages": [...]
}
```

### Step 7: Refresh When Expired

```
POST https://console.anthropic.com/v1/oauth/token
Content-Type: application/json

{
  "grant_type": "refresh_token",
  "refresh_token": "sk-ant-ort-...",
  "client_id": "9d1c250a-e61b-44d9-88ed-5944d1962f5e"
}
```

## Auth Modes

We support two authentication modes:

### `AuthMode::Max` (Claude Pro/Max)

- OAuth URL: `https://claude.ai/oauth/authorize`
- Uses your Claude subscription
- No per-token costs
- Requires active Pro/Max subscription

### `AuthMode::Console` (API Key)

- OAuth URL: `https://console.anthropic.com/oauth/authorize`
- Creates an API key programmatically
- Standard API pricing applies

## Token Types

| Prefix | Type | Description |
|--------|------|-------------|
| `sk-ant-oat-` | OAuth Access Token | Short-lived, used for API requests |
| `sk-ant-ort-` | OAuth Refresh Token | Long-lived, used to get new access tokens |
| `sk-ant-api-` | API Key | Traditional API key (not OAuth) |

## Required Headers

For OAuth tokens to work, requests MUST include:

```
Authorization: Bearer {access_token}
User-Agent: claude-cli/2.1.2 (external, cli)
anthropic-beta: oauth-2025-04-20,interleaved-thinking-2025-05-14
anthropic-version: 2023-06-01
x-app: cli
```

And the URL must have `?beta=true`:
```
POST /v1/messages?beta=true
```

## Request Requirements

OAuth tokens are validated against Claude Code's expected format. Requests MUST:

1. **Include system prompt**: Start with "You are Claude Code, Anthropic's official CLI for Claude."

2. **Include tools array**: Even if empty: `"tools": []`

3. **Prefix tool names**: All tool names must start with `mcp_` (e.g., `mcp_read_file`)

4. **Sanitize content**: Replace "OpenCode" with "Claude Code" in system prompts

## Sequence Diagram

```
┌────┐          ┌─────┐          ┌───────┐          ┌─────────┐
│User│          │ CLI │          │Anthropic         │   API   │
└─┬──┘          └──┬──┘          │  OAuth │          └────┬────┘
  │                │              └───┬───┘               │
  │  run cli       │                  │                   │
  │───────────────▶│                  │                   │
  │                │                  │                   │
  │                │  1. Generate PKCE                    │
  │                │──────┐           │                   │
  │                │      │           │                   │
  │                │◀─────┘           │                   │
  │                │                  │                   │
  │ 2. Open URL    │                  │                   │
  │◀───────────────│                  │                   │
  │                │                  │                   │
  │ 3. Authorize ─────────────────────▶                   │
  │                │                  │                   │
  │ 4. Get code  ◀─────────────────────                   │
  │                │                  │                   │
  │ 5. Paste code  │                  │                   │
  │───────────────▶│                  │                   │
  │                │                  │                   │
  │                │ 6. Exchange code │                   │
  │                │─────────────────▶│                   │
  │                │                  │                   │
  │                │ 7. Tokens        │                   │
  │                │◀─────────────────│                   │
  │                │                  │                   │
  │                │ 8. Save tokens   │                   │
  │                │──────┐           │                   │
  │                │      │           │                   │
  │                │◀─────┘           │                   │
  │                │                  │                   │
  │ 9. Chat        │                  │                   │
  │───────────────▶│                  │                   │
  │                │                  │                   │
  │                │ 10. Transform request                │
  │                │──────┐           │                   │
  │                │      │           │                   │
  │                │◀─────┘           │                   │
  │                │                  │                   │
  │                │ 11. API request ─────────────────────▶
  │                │                  │                   │
  │                │ 12. Response    ◀─────────────────────
  │                │                  │                   │
  │                │ 13. Transform response               │
  │                │──────┐           │                   │
  │                │      │           │                   │
  │                │◀─────┘           │                   │
  │                │                  │                   │
  │ 14. Display    │                  │                   │
  │◀───────────────│                  │                   │
  │                │                  │                   │
```

## Token Storage

Tokens are stored in JSON format at `~/.porta/tokens.json`:

```json
{
  "access_token": "sk-ant-oat-...",
  "refresh_token": "sk-ant-ort-...",
  "expires_at": 1710456789000
}
```

The `expires_at` is a Unix timestamp in milliseconds.
