Skip to content

Feature Request: Support Claude Subscription Auth (OAuth) as Alternative to API Keys #46

@henrikrexed

Description

@henrikrexed

Problem Statement

Currently, Sympozium only supports API key authentication for LLM providers via authSecretRef in AgentRun and authRefs in SympoziumInstance. This means users must have a paid API account with per-token billing.

However, many developers and teams already have Claude Pro/Team/Enterprise subscriptions (flat-rate) that include API access. These subscriptions authenticate via OAuth, not API keys. Today there's no way to use a Claude subscription with Sympozium — users are forced to pay twice (subscription + API tokens).

Use Case

As a developer with a Claude Pro subscription, I want to use my existing subscription to power Sympozium agents, so that:

  • I don't need a separate API key with per-token billing
  • My team can share our Claude Team/Enterprise subscription across Sympozium instances
  • We can leverage our existing Anthropic billing relationship
  • Air-gapped environments can pre-authenticate without storing long-lived API keys

As a team lead, I want my organization's Claude Enterprise workspace to be the auth backend for all our Sympozium agents, with centralized billing and access control.

Current Auth Flow (API Key)

apiVersion: sympozium.ai/v1alpha1
kind: SympoziumInstance
spec:
  authRefs:
    - provider: anthropic
      secret: anthropic-api-key    # K8s Secret containing API key
  agents:
    default:
      model: claude-sonnet-4-20250514
apiVersion: sympozium.ai/v1alpha1
kind: AgentRun
spec:
  model:
    model: claude-sonnet-4-20250514
    provider: anthropic
    authSecretRef: anthropic-api-key    # Must be API key

Proposed Solution

Add OAuth auth mode to authRefs

apiVersion: sympozium.ai/v1alpha1
kind: SympoziumInstance
spec:
  authRefs:
    - provider: anthropic
      mode: oauth                           # NEW: "apikey" (default) or "oauth"
      secret: anthropic-oauth-credentials   # K8s Secret with OAuth tokens

The Secret would contain the OAuth refresh token (same format as Claude Code CLI's ~/.claude/credentials.json):

apiVersion: v1
kind: Secret
metadata:
  name: anthropic-oauth-credentials
type: Opaque
stringData:
  oauth-token: "eyJ..."
  refresh-token: "eyJ..."
  expires-at: "2026-04-01T00:00:00Z"

Controller handles token refresh

Since agent pods are ephemeral, the Sympozium controller should handle the OAuth token lifecycle:

  1. Watch the OAuth credentials Secret
  2. Before token expiry, refresh it via Anthropic's OAuth endpoint
  3. Update the Secret with the new access token
  4. Agent pods always get a valid token when they start
User authenticates once (OAuth flow)
        ↓
Controller stores refresh token in K8s Secret
        ↓
Controller auto-refreshes access token before expiry
        ↓
AgentRun pods mount fresh access token
        ↓
Agent makes API calls with Bearer token (not x-api-key)

Initial authentication

Two options for the initial OAuth setup:

Option A: CLI-based (simplest)

# User authenticates via Claude CLI
claude login

# Extract credentials and create K8s secret
kubectl create secret generic anthropic-oauth \
  --from-file=credentials=$HOME/.claude/credentials.json

Option B: Web endpoint OAuth flow
If Sympozium's web endpoint is enabled, add an OAuth callback endpoint:

GET /auth/anthropic/login    → redirects to Anthropic OAuth
GET /auth/anthropic/callback → receives token, creates/updates Secret

AgentRun changes

The AgentRun CRD would need a new auth mode:

spec:
  model:
    model: claude-sonnet-4-20250514
    provider: anthropic
    authMode: oauth                          # NEW: "apikey" (default) or "oauth"
    authSecretRef: anthropic-oauth-credentials

The agent runner would use Authorization: Bearer <token> instead of x-api-key: <key> when authMode: oauth.

Implementation Considerations

API differences

Aspect API Key Auth OAuth Auth
Header x-api-key: sk-ant-... Authorization: Bearer eyJ...
Token lifetime Permanent (until revoked) Short-lived (needs refresh)
Rate limits Per-key limits Per-subscription limits
Billing Per-token Flat rate (subscription tier)
Setup Create key in console OAuth flow (one-time)

Security considerations

  • OAuth refresh tokens should be stored encrypted (K8s Secret + optional Vault)
  • Token refresh should happen server-side (controller), never in agent pods
  • Failed refresh should alert the operator (not silently fall back to no auth)
  • Audit log: which instance/agent used which auth credentials

Provider support

This pattern could extend beyond Anthropic:

Provider Auth Mode Notes
Anthropic OAuth Claude Pro/Team/Enterprise subscriptions
OpenAI OAuth ChatGPT Plus/Team/Enterprise
Google Service Account / OAuth Vertex AI, Gemini API
GitHub Copilot OAuth GitHub Copilot subscription

Benefits

  1. Cost savings: Teams already paying for subscriptions don't need separate API billing
  2. Simpler onboarding: No API key management, just "login with your Claude account"
  3. Enterprise-friendly: Works with SSO, centralized billing, workspace policies
  4. Security: Short-lived tokens vs permanent API keys
  5. Claude Code parity: Same auth mechanism as Claude Code CLI — users familiar with it

Prior Art

  • Claude Code CLI uses OAuth via claude login — stores credentials at ~/.claude/credentials.json
  • OpenClaw supports multiple auth profiles including OAuth-based providers
  • GitHub Actions uses OIDC tokens for cloud provider auth (similar pattern)

Summary

Approach Complexity User Impact
CLI-based OAuth setup + controller refresh Medium High — eliminates API key requirement
Web endpoint OAuth flow High Higher — zero-CLI setup possible

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions