From 277ad83552abfb24a9a2bd7d5ab0bf87a9ac4f3f Mon Sep 17 00:00:00 2001 From: waterystone Date: Tue, 2 Jun 2026 18:26:27 +0800 Subject: [PATCH] fix(anthropic): support ANTHROPIC_AUTH_TOKEN as alternative to ANTHROPIC_API_KEY (#853) * fix(anthropic): support ANTHROPIC_AUTH_TOKEN as alternative to ANTHROPIC_API_KEY Anthropic SDK supports two mutually exclusive auth methods: apiKey (sent as x-api-key header) and authToken (sent as Authorization: Bearer header). Detect either env var during provider detection and credential validation, and pass authToken to createAnthropic when only ANTHROPIC_AUTH_TOKEN is set. * docs(anthropic): document ANTHROPIC_AUTH_TOKEN and refine error message - Add ANTHROPIC_AUTH_TOKEN to env.example and the en/cn/ja provider docs - Reword the missing-credential error to "Either ... or ..." for readability --------- Co-authored-by: duyunjie Co-authored-by: dayuan.jiang --- docs/cn/ai-providers.md | 7 +++++++ docs/en/ai-providers.md | 7 +++++++ docs/ja/ai-providers.md | 7 +++++++ env.example | 3 ++- lib/ai-providers.ts | 45 +++++++++++++++++++++++++++++++++-------- 5 files changed, 60 insertions(+), 9 deletions(-) diff --git a/docs/cn/ai-providers.md b/docs/cn/ai-providers.md index dde047d..8266cbf 100644 --- a/docs/cn/ai-providers.md +++ b/docs/cn/ai-providers.md @@ -53,6 +53,13 @@ ANTHROPIC_API_KEY=your_api_key AI_MODEL=claude-sonnet-4-5-20250514 ``` +或者使用 Bearer 认证令牌(例如通过会下发 OAuth 风格 token 的网关时)。`ANTHROPIC_AUTH_TOKEN` 会作为 `Authorization: Bearer ` 头发送,而 `ANTHROPIC_API_KEY` 会作为 `x-api-key` 头发送。两者互斥,只能设置其中之一: + +```bash +ANTHROPIC_AUTH_TOKEN=your_auth_token +AI_MODEL=claude-sonnet-4-5-20250514 +``` + 可选的自定义端点: ```bash diff --git a/docs/en/ai-providers.md b/docs/en/ai-providers.md index c3eef58..0a77361 100644 --- a/docs/en/ai-providers.md +++ b/docs/en/ai-providers.md @@ -68,6 +68,13 @@ ANTHROPIC_API_KEY=your_api_key AI_MODEL=claude-sonnet-4-5-20250514 ``` +Or use a Bearer auth token instead of an API key (e.g. when going through a gateway that issues OAuth-style tokens). `ANTHROPIC_AUTH_TOKEN` is sent as `Authorization: Bearer `, while `ANTHROPIC_API_KEY` is sent as `x-api-key`. The two are mutually exclusive — set only one: + +```bash +ANTHROPIC_AUTH_TOKEN=your_auth_token +AI_MODEL=claude-sonnet-4-5-20250514 +``` + Optional custom endpoint: ```bash diff --git a/docs/ja/ai-providers.md b/docs/ja/ai-providers.md index fe9d3b6..f3bdbe2 100644 --- a/docs/ja/ai-providers.md +++ b/docs/ja/ai-providers.md @@ -53,6 +53,13 @@ ANTHROPIC_API_KEY=your_api_key AI_MODEL=claude-sonnet-4-5-20250514 ``` +または、Bearer 認証トークンを使用することもできます(OAuth スタイルのトークンを発行するゲートウェイ経由で利用する場合など)。`ANTHROPIC_AUTH_TOKEN` は `Authorization: Bearer ` ヘッダーで送信され、`ANTHROPIC_API_KEY` は `x-api-key` ヘッダーで送信されます。両者は排他的なので、いずれか一方のみを設定してください: + +```bash +ANTHROPIC_AUTH_TOKEN=your_auth_token +AI_MODEL=claude-sonnet-4-5-20250514 +``` + 任意のカスタムエンドポイント: ```bash diff --git a/env.example b/env.example index a9bc5ff..47a500d 100644 --- a/env.example +++ b/env.example @@ -25,7 +25,8 @@ AI_MODEL=global.anthropic.claude-sonnet-4-5-20250929-v1:0 # OPENAI_REASONING_SUMMARY=detailed # Optional: Override reasoning summary (none/brief/detailed) # Anthropic (Direct) Configuration -# ANTHROPIC_API_KEY=sk-ant-... +# ANTHROPIC_API_KEY=sk-ant-... # Sent as `x-api-key` header +# ANTHROPIC_AUTH_TOKEN= # Alternative to ANTHROPIC_API_KEY; sent as `Authorization: Bearer` header (mutually exclusive) # ANTHROPIC_BASE_URL=https://your-custom-anthropic/v1 # ANTHROPIC_THINKING_TYPE=enabled # Optional: Anthropic extended thinking (enabled) # ANTHROPIC_THINKING_BUDGET_TOKENS=12000 # Optional: Budget for extended thinking in tokens diff --git a/lib/ai-providers.ts b/lib/ai-providers.ts index bc689e3..49039de 100644 --- a/lib/ai-providers.ts +++ b/lib/ai-providers.ts @@ -573,7 +573,15 @@ function detectProvider(): ProviderName | null { // Skip ollama - it doesn't require credentials continue } - if (process.env[envVar]) { + // Anthropic accepts ANTHROPIC_AUTH_TOKEN (Bearer auth) as alternative to ANTHROPIC_API_KEY + const hasCredential = + provider === "anthropic" + ? !!( + process.env.ANTHROPIC_API_KEY || + process.env.ANTHROPIC_AUTH_TOKEN + ) + : !!process.env[envVar] + if (hasCredential) { // Azure requires additional config (baseURL or resourceName) if (provider === "azure") { const hasBaseUrl = !!process.env.AZURE_BASE_URL @@ -615,13 +623,26 @@ function validateProviderCredentials( return } - // Use custom env var name if provided, otherwise use default - const requiredVar = customApiKeyEnv || PROVIDER_ENV_VARS[provider] - if (requiredVar && !process.env[requiredVar]) { - throw new Error( - `${requiredVar} environment variable is required for ${provider} provider. ` + - `Please set it in your .env.local file.`, + // Anthropic accepts ANTHROPIC_AUTH_TOKEN (Bearer auth) as alternative to ANTHROPIC_API_KEY + if (provider === "anthropic" && !customApiKeyEnv) { + const hasCredential = !!( + process.env.ANTHROPIC_API_KEY || process.env.ANTHROPIC_AUTH_TOKEN ) + if (!hasCredential) { + throw new Error( + `Either ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN environment variable is required for anthropic provider. ` + + `Please set one in your .env.local file.`, + ) + } + } else { + // Use custom env var name if provided, otherwise use default + const requiredVar = customApiKeyEnv || PROVIDER_ENV_VARS[provider] + if (requiredVar && !process.env[requiredVar]) { + throw new Error( + `${requiredVar} environment variable is required for ${provider} provider. ` + + `Please set it in your .env.local file.`, + ) + } } // Azure requires either AZURE_BASE_URL or AZURE_RESOURCE_NAME in addition to API key @@ -845,8 +866,16 @@ export function getAIModel(overrides?: ClientOverrides): ModelConfig { serverBaseUrl, "https://api.anthropic.com/v1", ) + // Anthropic supports two auth methods (mutually exclusive): + // - apiKey: sends as `x-api-key` header + // - authToken: sends as `Authorization: Bearer ` header + // Prefer apiKey if present (including client overrides); fall back + // to ANTHROPIC_AUTH_TOKEN env var only when no apiKey is available. + const authToken = !apiKey + ? process.env.ANTHROPIC_AUTH_TOKEN + : undefined const customProvider = createAnthropic({ - apiKey, + ...(authToken ? { authToken } : { apiKey }), baseURL, headers: ANTHROPIC_BETA_HEADERS, })