fix(auth): remove ANTHROPIC_API_KEY fallback to prevent silent billing

Remove ANTHROPIC_API_KEY from the authentication fallback chain.
Auto Claude is designed to use Claude Code OAuth tokens only.

Previously, if CLAUDE_CODE_OAUTH_TOKEN was empty or missing, the system
would silently fall back to ANTHROPIC_API_KEY from the environment,
causing unexpected API billing when users thought they were using OAuth.

Closes #76

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
This commit is contained in:
AndyMik90
2025-12-20 18:38:12 +01:00
co-authored by Claude Opus 4.5
parent 12c8519246
commit c52caa6b17
3 changed files with 39 additions and 25 deletions
+7 -6
View File
@@ -2,16 +2,17 @@
# Copy this file to .env and fill in your values
# =============================================================================
# AUTHENTICATION (REQUIRED - set ONE of the following)
# AUTHENTICATION (REQUIRED)
# =============================================================================
# The framework checks these in order of priority:
# 1. CLAUDE_CODE_OAUTH_TOKEN - Original (from `claude setup-token`)
# 2. ANTHROPIC_AUTH_TOKEN - For proxies like CCR
# 3. ANTHROPIC_API_KEY - Direct Anthropic API key
# Auto Claude uses Claude Code OAuth authentication.
# Direct API keys (ANTHROPIC_API_KEY) are NOT supported to prevent silent billing.
#
# Option 1: Run `claude setup-token` to save token to macOS Keychain (recommended)
# Option 2: Set the token explicitly:
# CLAUDE_CODE_OAUTH_TOKEN=your-oauth-token-here
#
# For enterprise/proxy setups (CCR):
# ANTHROPIC_AUTH_TOKEN=sk-zcf-x-ccr
# ANTHROPIC_API_KEY=sk-ant-...
# =============================================================================
# CUSTOM API ENDPOINT (OPTIONAL)
+7 -8
View File
@@ -96,20 +96,19 @@ def validate_environment(spec_dir: Path) -> bool:
"""
valid = True
# Check for authentication token (supports multiple env vars)
# Check for OAuth token (API keys are not supported)
if not get_auth_token():
print("Error: No authentication token found")
print(f"\nSet one of: {', '.join(AUTH_TOKEN_ENV_VARS)}")
print("\nFor Claude Code CLI, get your OAuth token by running:")
print("Error: No OAuth token found")
print("\nAuto Claude requires Claude Code OAuth authentication.")
print("Direct API keys (ANTHROPIC_API_KEY) are not supported.")
print("\nTo authenticate, run:")
print(" claude setup-token")
print("\nThen set it:")
print(" export CLAUDE_CODE_OAUTH_TOKEN='your-token-here'")
valid = False
else:
# Show which auth source is being used
source = get_auth_token_source()
if source and source != "CLAUDE_CODE_OAUTH_TOKEN":
print(f"Auth: Using token from {source}")
if source:
print(f"Auth: {source}")
# Show custom base URL if set
base_url = os.environ.get("ANTHROPIC_BASE_URL")
+25 -11
View File
@@ -12,17 +12,19 @@ import platform
import subprocess
# Priority order for auth token resolution
# NOTE: We intentionally do NOT fall back to ANTHROPIC_API_KEY.
# Auto Claude is designed to use Claude Code OAuth tokens only.
# This prevents silent billing to user's API credits when OAuth fails.
AUTH_TOKEN_ENV_VARS = [
"CLAUDE_CODE_OAUTH_TOKEN", # Original (highest priority)
"ANTHROPIC_AUTH_TOKEN", # CCR/proxy token
"ANTHROPIC_API_KEY", # Direct API key (lowest priority)
"CLAUDE_CODE_OAUTH_TOKEN", # OAuth token from Claude Code CLI
"ANTHROPIC_AUTH_TOKEN", # CCR/proxy token (for enterprise setups)
]
# Environment variables to pass through to SDK subprocess
# NOTE: ANTHROPIC_API_KEY is intentionally excluded to prevent silent API billing
SDK_ENV_VARS = [
"ANTHROPIC_BASE_URL",
"ANTHROPIC_AUTH_TOKEN",
"ANTHROPIC_API_KEY",
"NO_PROXY",
"DISABLE_TELEMETRY",
"DISABLE_COST_WARNINGS",
@@ -92,9 +94,11 @@ def get_auth_token() -> str | None:
Checks multiple sources in priority order:
1. CLAUDE_CODE_OAUTH_TOKEN (env var)
2. ANTHROPIC_AUTH_TOKEN (ccr/proxy env var)
3. ANTHROPIC_API_KEY (direct API key env var)
4. macOS Keychain (if on Darwin platform)
2. ANTHROPIC_AUTH_TOKEN (CCR/proxy env var for enterprise setups)
3. macOS Keychain (if on Darwin platform)
NOTE: ANTHROPIC_API_KEY is intentionally NOT supported to prevent
silent billing to user's API credits when OAuth is misconfigured.
Returns:
Token string if found, None otherwise
@@ -133,14 +137,24 @@ def require_auth_token() -> str:
token = get_auth_token()
if not token:
error_msg = (
"No authentication token found.\n"
f"Set one of: {', '.join(AUTH_TOKEN_ENV_VARS)}\n"
"No OAuth token found.\n\n"
"Auto Claude requires Claude Code OAuth authentication.\n"
"Direct API keys (ANTHROPIC_API_KEY) are not supported.\n\n"
)
# Provide platform-specific guidance
if platform.system() == "Darwin":
error_msg += "For Claude Code CLI: run 'claude setup-token' to save token to macOS Keychain"
error_msg += (
"To authenticate:\n"
" 1. Run: claude setup-token\n"
" 2. The token will be saved to macOS Keychain automatically\n\n"
"Or set CLAUDE_CODE_OAUTH_TOKEN in your .env file."
)
else:
error_msg += "For Claude Code CLI: run 'claude setup-token'"
error_msg += (
"To authenticate:\n"
" 1. Run: claude setup-token\n"
" 2. Set CLAUDE_CODE_OAUTH_TOKEN in your .env file"
)
raise ValueError(error_msg)
return token