# How OAuth Authentication Works for Claude Code, Cursor, and Cline in OmniRoute

> Explore how OmniRoute uses OAuth authentication for Claude Code, Cursor, and Cline. Learn about the Authorization Code flow with PKCE and metadata retrieval.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-08-03

---

**OmniRoute implements OAuth authentication for Claude Code, Cursor, and Cline using the standard Authorization Code flow with PKCE, with provider-specific extensions for account metadata retrieval.**

The diegosouzapw/OmniRoute repository provides a unified OAuth layer that handles authentication across three popular AI coding assistants. All three providers authenticate against Anthropic's OAuth infrastructure via [`src/lib/oauth/providers/claude.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/oauth/providers/claude.ts), while Cursor and Cline reuse the same core logic through thin wrapper modules.

## OAuth Flow Overview: Authorization Code with PKCE

Every provider follows the same six-step sequence. The implementation in [`src/lib/oauth/providers/claude.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/oauth/providers/claude.ts) serves as the foundation, with Cursor and Cline inheriting or reusing these methods.

### Step 1: Build the Authorization URL

The `buildAuthUrl` method constructs the initial redirect to Anthropic's OAuth endpoint.

```typescript
// src/lib/oauth/providers/claude.ts#L82-L100
const authUrl = provider.buildAuthUrl(
  provider.config,
  "http://localhost:3000/callback",
  state,           // cryptographically random UUID
  codeChallenge,   // PKCE S256 code challenge
);

```

Key parameters include:
- `client_id` — registered application identifier
- `code_challenge` — PKCE challenge for proof key
- `scope` — requested permissions (typically `offline_access`)
- `prompt=login` — forces re-authentication to prevent token reuse
- `state` — CSRF protection token

### Step 2: User Authorization

The user completes authentication in their browser. Anthropic redirects back to the configured callback with an authorization code and the original state parameter for validation.

### Step 3: Exchange Code for Tokens

The `exchangeToken` method posts to Anthropic's token endpoint.

```typescript
// src/lib/oauth/providers/claude.ts#L103-L126
const tokenResponse = await provider.exchangeToken(
  provider.config,
  authCode,        // from callback query parameter
  redirectUri,
  codeVerifier,    // original PKCE verifier
  state,
);

```

The response contains `access_token`, `refresh_token`, `expires_in`, and `scope`.

### Step 4: Post-Exchange Bootstrap (Claude Code Only)

Claude Code requires an additional API call to retrieve account metadata.

```typescript
// src/lib/oauth/providers/claude.ts#L135-L140
const bootstrapData = await provider.postExchange(tokenResponse);
// POST https://api.anthropic.com/api/claude_cli/bootstrap
// Authorization: Bearer {access_token}

```

This endpoint returns `account_uuid`, `organization_uuid`, email, and subscription `plan` — data not present in the standard OAuth token response.

### Step 5: Map Tokens to OmniRoute's Internal Format

The `mapTokens` method normalizes provider responses into a consistent connection object.

```typescript
// src/lib/oauth/providers/claude.ts#L140-L168
const connectionInfo = provider.mapTokens(
  tokenResponse,
  await provider.postExchange(tokenResponse) // null for Cursor/Cline
);

```

The resulting structure includes:
- Standard OAuth fields: `accessToken`, `refreshToken`, `expiresIn`, `scope`
- Identity fields: `email`
- Provider-specific data: `cliUserID`, `accountUUID`, `organizationName`, `plan`

### Step 6: Token Refresh

Refresh operations reuse `exchangeToken` logic with `grant_type=refresh_token`. The same mapping pipeline updates stored credentials.

## Provider-Specific Implementations

### Claude Code OAuth Authentication

Claude Code is the most complex provider due to the bootstrap requirement. The full implementation resides in [`src/lib/oauth/providers/claude.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/oauth/providers/claude.ts) with three key methods:

- `buildAuthUrl` — constructs Anthropic authorization URL
- `exchangeToken` — performs code exchange
- `postExchange` — fetches `/claude_cli/bootstrap` metadata
- `mapTokens` — merges OAuth and bootstrap data

The bootstrap response is cached as `providerSpecificData` for downstream authorization decisions.

### Cursor OAuth Authentication

Cursor reuses the generic flow without the Claude-specific bootstrap call. The implementation in [`src/lib/oauth/providers/cursor.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/oauth/providers/cursor.ts) mirrors [`claude.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/claude.ts) but omits `postExchange`. Token response fields alone satisfy OmniRoute's connection requirements.

```typescript
// Cursor provider imports and reexports from claude.ts
// with postExchange overridden to return null

```

### Cline OAuth Authentication

Cline follows the same pattern as Cursor. The [`src/lib/oauth/providers/cline.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/oauth/providers/cline.ts) module is a thin wrapper that delegates to the generic OAuth helpers registered in the provider index.

## Complete OAuth Implementation Example

```typescript
import { getProvider } from "@/lib/oauth/providers";

// Initialize provider (claude | cursor | cline)
const provider = getProvider("cursor");

// Generate PKCE pair
const codeVerifier = crypto.randomBytes(32).toString("base64url");
const codeChallenge = await sha256(codeVerifier);

// Step 1: Build authorization URL
const state = crypto.randomUUID();
const authUrl = provider.buildAuthUrl(
  provider.config,
  process.env.OAUTH_REDIRECT_URI,
  state,
  codeChallenge,
);

// After user returns with authorization code...
// Step 2-3: Exchange for tokens
const tokenResponse = await provider.exchangeToken(
  provider.config,
  req.query.code,
  process.env.OAUTH_REDIRECT_URI,
  codeVerifier,
  req.query.state,
);

// Step 4-5: Normalize and store
const extras = await provider.postExchange(tokenResponse);
const connection = provider.mapTokens(tokenResponse, extras);

await db.connections.insert({
  provider: "cursor",
  ...connection,
});

```

## Provider Registration

All three providers are declared in [`src/shared/constants/providers/oauth.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/constants/providers/oauth.ts):

```typescript
export const OAUTH_PROVIDERS = {
  claude: {
    authType: "oauth",
    module: "@/lib/oauth/providers/claude",
    endpoints: {
      authorize: "https://auth.anthropic.com/oauth/authorize",
      token: "https://auth.anthropic.com/oauth/token",
    },
  },
  cursor: { /* inherits claude endpoints */ },
  cline: { /* inherits claude endpoints */ },
} as const;

```

The `getProvider` factory in [`src/lib/oauth/providers/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/oauth/providers/index.ts) loads the correct module based on the provider ID.

## Summary

- **All three providers** use Authorization Code with PKCE against Anthropic's OAuth infrastructure
- **Claude Code** uniquely requires a bootstrap call to `/claude_cli/bootstrap` for account metadata
- **Cursor and Cline** reuse the generic flow without provider-specific extensions
- **Core implementation** lives in [`src/lib/oauth/providers/claude.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/oauth/providers/claude.ts) with thin wrappers for the other providers
- **Token mapping** produces a normalized connection object with `providerSpecificData` for downstream use

## Frequently Asked Questions

### What OAuth grant type does OmniRoute use for Claude Code, Cursor, and Cline?

OmniRoute uses the **Authorization Code grant with PKCE** (Proof Key for Code Exchange). This is the modern standard for native and browser-based applications. The PKCE `code_challenge` prevents authorization code interception attacks. All three providers implement this identically in [`src/lib/oauth/providers/claude.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/oauth/providers/claude.ts).

### Why does Claude Code require a separate bootstrap API call?

The bootstrap endpoint at `https://api.anthropic.com/api/claude_cli/bootstrap` returns **account and organization metadata** that Anthropic does not include in the OAuth token response. This includes `account_uuid`, `organization_uuid`, email, and subscription `plan`. OmniRoute caches this as `providerSpecificData` for authorization and feature-gating decisions. Cursor and Cline do not need this call because their use cases do not require organization-level metadata.

### How does OmniRoute handle token refresh for these providers?

Refresh operations **reuse the same `exchangeToken` method** with `grant_type=refresh_token`. The stored `refresh_token` from the initial connection is posted to Anthropic's token endpoint. The refreshed tokens flow through the identical `mapTokens` pipeline, updating the connection record with new access and refresh tokens. This ensures consistent data shapes across initial grants and refreshes.