source dump of claude code
at main 234 lines 9.0 kB view raw
1import { isEnvTruthy } from 'src/utils/envUtils.js' 2 3// Default to prod config, override with test/staging if enabled 4type OauthConfigType = 'prod' | 'staging' | 'local' 5 6function getOauthConfigType(): OauthConfigType { 7 if (process.env.USER_TYPE === 'ant') { 8 if (isEnvTruthy(process.env.USE_LOCAL_OAUTH)) { 9 return 'local' 10 } 11 if (isEnvTruthy(process.env.USE_STAGING_OAUTH)) { 12 return 'staging' 13 } 14 } 15 return 'prod' 16} 17 18export function fileSuffixForOauthConfig(): string { 19 if (process.env.CLAUDE_CODE_CUSTOM_OAUTH_URL) { 20 return '-custom-oauth' 21 } 22 switch (getOauthConfigType()) { 23 case 'local': 24 return '-local-oauth' 25 case 'staging': 26 return '-staging-oauth' 27 case 'prod': 28 // No suffix for production config 29 return '' 30 } 31} 32 33export const CLAUDE_AI_INFERENCE_SCOPE = 'user:inference' as const 34export const CLAUDE_AI_PROFILE_SCOPE = 'user:profile' as const 35const CONSOLE_SCOPE = 'org:create_api_key' as const 36export const OAUTH_BETA_HEADER = 'oauth-2025-04-20' as const 37 38// Console OAuth scopes - for API key creation via Console 39export const CONSOLE_OAUTH_SCOPES = [ 40 CONSOLE_SCOPE, 41 CLAUDE_AI_PROFILE_SCOPE, 42] as const 43 44// Claude.ai OAuth scopes - for Claude.ai subscribers (Pro/Max/Team/Enterprise) 45export const CLAUDE_AI_OAUTH_SCOPES = [ 46 CLAUDE_AI_PROFILE_SCOPE, 47 CLAUDE_AI_INFERENCE_SCOPE, 48 'user:sessions:claude_code', 49 'user:mcp_servers', 50 'user:file_upload', 51] as const 52 53// All OAuth scopes - union of all scopes used in Claude CLI 54// When logging in, request all scopes in order to handle both Console -> Claude.ai redirect 55// Ensure that `OAuthConsentPage` in apps repo is kept in sync with this list. 56export const ALL_OAUTH_SCOPES = Array.from( 57 new Set([...CONSOLE_OAUTH_SCOPES, ...CLAUDE_AI_OAUTH_SCOPES]), 58) 59 60type OauthConfig = { 61 BASE_API_URL: string 62 CONSOLE_AUTHORIZE_URL: string 63 CLAUDE_AI_AUTHORIZE_URL: string 64 /** 65 * The claude.ai web origin. Separate from CLAUDE_AI_AUTHORIZE_URL because 66 * that now routes through claude.com/cai/* for attribution — deriving 67 * .origin from it would give claude.com, breaking links to /code, 68 * /settings/connectors, and other claude.ai web pages. 69 */ 70 CLAUDE_AI_ORIGIN: string 71 TOKEN_URL: string 72 API_KEY_URL: string 73 ROLES_URL: string 74 CONSOLE_SUCCESS_URL: string 75 CLAUDEAI_SUCCESS_URL: string 76 MANUAL_REDIRECT_URL: string 77 CLIENT_ID: string 78 OAUTH_FILE_SUFFIX: string 79 MCP_PROXY_URL: string 80 MCP_PROXY_PATH: string 81} 82 83// Production OAuth configuration - Used in normal operation 84const PROD_OAUTH_CONFIG = { 85 BASE_API_URL: 'https://api.anthropic.com', 86 CONSOLE_AUTHORIZE_URL: 'https://platform.claude.com/oauth/authorize', 87 // Bounces through claude.com/cai/* so CLI sign-ins connect to claude.com 88 // visits for attribution. 307s to claude.ai/oauth/authorize in two hops. 89 CLAUDE_AI_AUTHORIZE_URL: 'https://claude.com/cai/oauth/authorize', 90 CLAUDE_AI_ORIGIN: 'https://claude.ai', 91 TOKEN_URL: 'https://platform.claude.com/v1/oauth/token', 92 API_KEY_URL: 'https://api.anthropic.com/api/oauth/claude_cli/create_api_key', 93 ROLES_URL: 'https://api.anthropic.com/api/oauth/claude_cli/roles', 94 CONSOLE_SUCCESS_URL: 95 'https://platform.claude.com/buy_credits?returnUrl=/oauth/code/success%3Fapp%3Dclaude-code', 96 CLAUDEAI_SUCCESS_URL: 97 'https://platform.claude.com/oauth/code/success?app=claude-code', 98 MANUAL_REDIRECT_URL: 'https://platform.claude.com/oauth/code/callback', 99 CLIENT_ID: '9d1c250a-e61b-44d9-88ed-5944d1962f5e', 100 // No suffix for production config 101 OAUTH_FILE_SUFFIX: '', 102 MCP_PROXY_URL: 'https://mcp-proxy.anthropic.com', 103 MCP_PROXY_PATH: '/v1/mcp/{server_id}', 104} as const 105 106/** 107 * Client ID Metadata Document URL for MCP OAuth (CIMD / SEP-991). 108 * When an MCP auth server advertises client_id_metadata_document_supported: true, 109 * Claude Code uses this URL as its client_id instead of Dynamic Client Registration. 110 * The URL must point to a JSON document hosted by Anthropic. 111 * See: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-client-id-metadata-document-00 112 */ 113export const MCP_CLIENT_METADATA_URL = 114 'https://claude.ai/oauth/claude-code-client-metadata' 115 116// Staging OAuth configuration - only included in ant builds with staging flag 117// Uses literal check for dead code elimination 118const STAGING_OAUTH_CONFIG = 119 process.env.USER_TYPE === 'ant' 120 ? ({ 121 BASE_API_URL: 'https://api-staging.anthropic.com', 122 CONSOLE_AUTHORIZE_URL: 123 'https://platform.staging.ant.dev/oauth/authorize', 124 CLAUDE_AI_AUTHORIZE_URL: 125 'https://claude-ai.staging.ant.dev/oauth/authorize', 126 CLAUDE_AI_ORIGIN: 'https://claude-ai.staging.ant.dev', 127 TOKEN_URL: 'https://platform.staging.ant.dev/v1/oauth/token', 128 API_KEY_URL: 129 'https://api-staging.anthropic.com/api/oauth/claude_cli/create_api_key', 130 ROLES_URL: 131 'https://api-staging.anthropic.com/api/oauth/claude_cli/roles', 132 CONSOLE_SUCCESS_URL: 133 'https://platform.staging.ant.dev/buy_credits?returnUrl=/oauth/code/success%3Fapp%3Dclaude-code', 134 CLAUDEAI_SUCCESS_URL: 135 'https://platform.staging.ant.dev/oauth/code/success?app=claude-code', 136 MANUAL_REDIRECT_URL: 137 'https://platform.staging.ant.dev/oauth/code/callback', 138 CLIENT_ID: '22422756-60c9-4084-8eb7-27705fd5cf9a', 139 OAUTH_FILE_SUFFIX: '-staging-oauth', 140 MCP_PROXY_URL: 'https://mcp-proxy-staging.anthropic.com', 141 MCP_PROXY_PATH: '/v1/mcp/{server_id}', 142 } as const) 143 : undefined 144 145// Three local dev servers: :8000 api-proxy (`api dev start -g ccr`), 146// :4000 claude-ai frontend, :3000 Console frontend. Env vars let 147// scripts/claude-localhost override if your layout differs. 148function getLocalOauthConfig(): OauthConfig { 149 const api = 150 process.env.CLAUDE_LOCAL_OAUTH_API_BASE?.replace(/\/$/, '') ?? 151 'http://localhost:8000' 152 const apps = 153 process.env.CLAUDE_LOCAL_OAUTH_APPS_BASE?.replace(/\/$/, '') ?? 154 'http://localhost:4000' 155 const consoleBase = 156 process.env.CLAUDE_LOCAL_OAUTH_CONSOLE_BASE?.replace(/\/$/, '') ?? 157 'http://localhost:3000' 158 return { 159 BASE_API_URL: api, 160 CONSOLE_AUTHORIZE_URL: `${consoleBase}/oauth/authorize`, 161 CLAUDE_AI_AUTHORIZE_URL: `${apps}/oauth/authorize`, 162 CLAUDE_AI_ORIGIN: apps, 163 TOKEN_URL: `${api}/v1/oauth/token`, 164 API_KEY_URL: `${api}/api/oauth/claude_cli/create_api_key`, 165 ROLES_URL: `${api}/api/oauth/claude_cli/roles`, 166 CONSOLE_SUCCESS_URL: `${consoleBase}/buy_credits?returnUrl=/oauth/code/success%3Fapp%3Dclaude-code`, 167 CLAUDEAI_SUCCESS_URL: `${consoleBase}/oauth/code/success?app=claude-code`, 168 MANUAL_REDIRECT_URL: `${consoleBase}/oauth/code/callback`, 169 CLIENT_ID: '22422756-60c9-4084-8eb7-27705fd5cf9a', 170 OAUTH_FILE_SUFFIX: '-local-oauth', 171 MCP_PROXY_URL: 'http://localhost:8205', 172 MCP_PROXY_PATH: '/v1/toolbox/shttp/mcp/{server_id}', 173 } 174} 175 176// Allowed base URLs for CLAUDE_CODE_CUSTOM_OAUTH_URL override. 177// Only FedStart/PubSec deployments are permitted to prevent OAuth tokens 178// from being sent to arbitrary endpoints. 179const ALLOWED_OAUTH_BASE_URLS = [ 180 'https://beacon.claude-ai.staging.ant.dev', 181 'https://claude.fedstart.com', 182 'https://claude-staging.fedstart.com', 183] 184 185// Default to prod config, override with test/staging if enabled 186export function getOauthConfig(): OauthConfig { 187 let config: OauthConfig = (() => { 188 switch (getOauthConfigType()) { 189 case 'local': 190 return getLocalOauthConfig() 191 case 'staging': 192 return STAGING_OAUTH_CONFIG ?? PROD_OAUTH_CONFIG 193 case 'prod': 194 return PROD_OAUTH_CONFIG 195 } 196 })() 197 198 // Allow overriding all OAuth URLs to point to an approved FedStart deployment. 199 // Only allowlisted base URLs are accepted to prevent credential leakage. 200 const oauthBaseUrl = process.env.CLAUDE_CODE_CUSTOM_OAUTH_URL 201 if (oauthBaseUrl) { 202 const base = oauthBaseUrl.replace(/\/$/, '') 203 if (!ALLOWED_OAUTH_BASE_URLS.includes(base)) { 204 throw new Error( 205 'CLAUDE_CODE_CUSTOM_OAUTH_URL is not an approved endpoint.', 206 ) 207 } 208 config = { 209 ...config, 210 BASE_API_URL: base, 211 CONSOLE_AUTHORIZE_URL: `${base}/oauth/authorize`, 212 CLAUDE_AI_AUTHORIZE_URL: `${base}/oauth/authorize`, 213 CLAUDE_AI_ORIGIN: base, 214 TOKEN_URL: `${base}/v1/oauth/token`, 215 API_KEY_URL: `${base}/api/oauth/claude_cli/create_api_key`, 216 ROLES_URL: `${base}/api/oauth/claude_cli/roles`, 217 CONSOLE_SUCCESS_URL: `${base}/oauth/code/success?app=claude-code`, 218 CLAUDEAI_SUCCESS_URL: `${base}/oauth/code/success?app=claude-code`, 219 MANUAL_REDIRECT_URL: `${base}/oauth/code/callback`, 220 OAUTH_FILE_SUFFIX: '-custom-oauth', 221 } 222 } 223 224 // Allow CLIENT_ID override via environment variable (e.g., for Xcode integration) 225 const clientIdOverride = process.env.CLAUDE_CODE_OAUTH_CLIENT_ID 226 if (clientIdOverride) { 227 config = { 228 ...config, 229 CLIENT_ID: clientIdOverride, 230 } 231 } 232 233 return config 234}