oauth.ts
constants/oauth.ts
235
Lines
8970
Bytes
9
Exports
1
Imports
10
Keywords
What this is
This page documents one file from the repository and includes its full source so you can read it without leaving the docs site.
Beginner explanation
This file is one piece of the larger system. Its name, directory, imports, and exports show where it fits. Start by reading the exports and related files first.
How it is used
Start from the exports list and related files. Those are the easiest clues for where this file fits into the system.
Expert explanation
Architecturally, this file intersects with integrations. It contains 235 lines, 1 detected imports, and 9 detected exports.
Important relationships
Detected exports
fileSuffixForOauthConfigCLAUDE_AI_INFERENCE_SCOPECLAUDE_AI_PROFILE_SCOPEOAUTH_BETA_HEADERCONSOLE_OAUTH_SCOPESCLAUDE_AI_OAUTH_SCOPESALL_OAUTH_SCOPESMCP_CLIENT_METADATA_URLgetOauthConfig
Keywords
oauthhttpsclaudestagingcodebaseconfigprocessplatformanthropic
Detected imports
src/utils/envUtils.js
Source notes
This page embeds the full file contents. Small or leaf files are still indexed honestly instead of being over-explained.
Full source
import { isEnvTruthy } from 'src/utils/envUtils.js'
// Default to prod config, override with test/staging if enabled
type OauthConfigType = 'prod' | 'staging' | 'local'
function getOauthConfigType(): OauthConfigType {
if (process.env.USER_TYPE === 'ant') {
if (isEnvTruthy(process.env.USE_LOCAL_OAUTH)) {
return 'local'
}
if (isEnvTruthy(process.env.USE_STAGING_OAUTH)) {
return 'staging'
}
}
return 'prod'
}
export function fileSuffixForOauthConfig(): string {
if (process.env.CLAUDE_CODE_CUSTOM_OAUTH_URL) {
return '-custom-oauth'
}
switch (getOauthConfigType()) {
case 'local':
return '-local-oauth'
case 'staging':
return '-staging-oauth'
case 'prod':
// No suffix for production config
return ''
}
}
export const CLAUDE_AI_INFERENCE_SCOPE = 'user:inference' as const
export const CLAUDE_AI_PROFILE_SCOPE = 'user:profile' as const
const CONSOLE_SCOPE = 'org:create_api_key' as const
export const OAUTH_BETA_HEADER = 'oauth-2025-04-20' as const
// Console OAuth scopes - for API key creation via Console
export const CONSOLE_OAUTH_SCOPES = [
CONSOLE_SCOPE,
CLAUDE_AI_PROFILE_SCOPE,
] as const
// Claude.ai OAuth scopes - for Claude.ai subscribers (Pro/Max/Team/Enterprise)
export const CLAUDE_AI_OAUTH_SCOPES = [
CLAUDE_AI_PROFILE_SCOPE,
CLAUDE_AI_INFERENCE_SCOPE,
'user:sessions:claude_code',
'user:mcp_servers',
'user:file_upload',
] as const
// All OAuth scopes - union of all scopes used in Claude CLI
// When logging in, request all scopes in order to handle both Console -> Claude.ai redirect
// Ensure that `OAuthConsentPage` in apps repo is kept in sync with this list.
export const ALL_OAUTH_SCOPES = Array.from(
new Set([...CONSOLE_OAUTH_SCOPES, ...CLAUDE_AI_OAUTH_SCOPES]),
)
type OauthConfig = {
BASE_API_URL: string
CONSOLE_AUTHORIZE_URL: string
CLAUDE_AI_AUTHORIZE_URL: string
/**
* The claude.ai web origin. Separate from CLAUDE_AI_AUTHORIZE_URL because
* that now routes through claude.com/cai/* for attribution — deriving
* .origin from it would give claude.com, breaking links to /code,
* /settings/connectors, and other claude.ai web pages.
*/
CLAUDE_AI_ORIGIN: string
TOKEN_URL: string
API_KEY_URL: string
ROLES_URL: string
CONSOLE_SUCCESS_URL: string
CLAUDEAI_SUCCESS_URL: string
MANUAL_REDIRECT_URL: string
CLIENT_ID: string
OAUTH_FILE_SUFFIX: string
MCP_PROXY_URL: string
MCP_PROXY_PATH: string
}
// Production OAuth configuration - Used in normal operation
const PROD_OAUTH_CONFIG = {
BASE_API_URL: 'https://api.anthropic.com',
CONSOLE_AUTHORIZE_URL: 'https://platform.claude.com/oauth/authorize',
// Bounces through claude.com/cai/* so CLI sign-ins connect to claude.com
// visits for attribution. 307s to claude.ai/oauth/authorize in two hops.
CLAUDE_AI_AUTHORIZE_URL: 'https://claude.com/cai/oauth/authorize',
CLAUDE_AI_ORIGIN: 'https://claude.ai',
TOKEN_URL: 'https://platform.claude.com/v1/oauth/token',
API_KEY_URL: 'https://api.anthropic.com/api/oauth/claude_cli/create_api_key',
ROLES_URL: 'https://api.anthropic.com/api/oauth/claude_cli/roles',
CONSOLE_SUCCESS_URL:
'https://platform.claude.com/buy_credits?returnUrl=/oauth/code/success%3Fapp%3Dclaude-code',
CLAUDEAI_SUCCESS_URL:
'https://platform.claude.com/oauth/code/success?app=claude-code',
MANUAL_REDIRECT_URL: 'https://platform.claude.com/oauth/code/callback',
CLIENT_ID: '9d1c250a-e61b-44d9-88ed-5944d1962f5e',
// No suffix for production config
OAUTH_FILE_SUFFIX: '',
MCP_PROXY_URL: 'https://mcp-proxy.anthropic.com',
MCP_PROXY_PATH: '/v1/mcp/{server_id}',
} as const
/**
* Client ID Metadata Document URL for MCP OAuth (CIMD / SEP-991).
* When an MCP auth server advertises client_id_metadata_document_supported: true,
* Claude Code uses this URL as its client_id instead of Dynamic Client Registration.
* The URL must point to a JSON document hosted by Anthropic.
* See: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-client-id-metadata-document-00
*/
export const MCP_CLIENT_METADATA_URL =
'https://claude.ai/oauth/claude-code-client-metadata'
// Staging OAuth configuration - only included in ant builds with staging flag
// Uses literal check for dead code elimination
const STAGING_OAUTH_CONFIG =
process.env.USER_TYPE === 'ant'
? ({
BASE_API_URL: 'https://api-staging.anthropic.com',
CONSOLE_AUTHORIZE_URL:
'https://platform.staging.ant.dev/oauth/authorize',
CLAUDE_AI_AUTHORIZE_URL:
'https://claude-ai.staging.ant.dev/oauth/authorize',
CLAUDE_AI_ORIGIN: 'https://claude-ai.staging.ant.dev',
TOKEN_URL: 'https://platform.staging.ant.dev/v1/oauth/token',
API_KEY_URL:
'https://api-staging.anthropic.com/api/oauth/claude_cli/create_api_key',
ROLES_URL:
'https://api-staging.anthropic.com/api/oauth/claude_cli/roles',
CONSOLE_SUCCESS_URL:
'https://platform.staging.ant.dev/buy_credits?returnUrl=/oauth/code/success%3Fapp%3Dclaude-code',
CLAUDEAI_SUCCESS_URL:
'https://platform.staging.ant.dev/oauth/code/success?app=claude-code',
MANUAL_REDIRECT_URL:
'https://platform.staging.ant.dev/oauth/code/callback',
CLIENT_ID: '22422756-60c9-4084-8eb7-27705fd5cf9a',
OAUTH_FILE_SUFFIX: '-staging-oauth',
MCP_PROXY_URL: 'https://mcp-proxy-staging.anthropic.com',
MCP_PROXY_PATH: '/v1/mcp/{server_id}',
} as const)
: undefined
// Three local dev servers: :8000 api-proxy (`api dev start -g ccr`),
// :4000 claude-ai frontend, :3000 Console frontend. Env vars let
// scripts/claude-localhost override if your layout differs.
function getLocalOauthConfig(): OauthConfig {
const api =
process.env.CLAUDE_LOCAL_OAUTH_API_BASE?.replace(/\/$/, '') ??
'http://localhost:8000'
const apps =
process.env.CLAUDE_LOCAL_OAUTH_APPS_BASE?.replace(/\/$/, '') ??
'http://localhost:4000'
const consoleBase =
process.env.CLAUDE_LOCAL_OAUTH_CONSOLE_BASE?.replace(/\/$/, '') ??
'http://localhost:3000'
return {
BASE_API_URL: api,
CONSOLE_AUTHORIZE_URL: `${consoleBase}/oauth/authorize`,
CLAUDE_AI_AUTHORIZE_URL: `${apps}/oauth/authorize`,
CLAUDE_AI_ORIGIN: apps,
TOKEN_URL: `${api}/v1/oauth/token`,
API_KEY_URL: `${api}/api/oauth/claude_cli/create_api_key`,
ROLES_URL: `${api}/api/oauth/claude_cli/roles`,
CONSOLE_SUCCESS_URL: `${consoleBase}/buy_credits?returnUrl=/oauth/code/success%3Fapp%3Dclaude-code`,
CLAUDEAI_SUCCESS_URL: `${consoleBase}/oauth/code/success?app=claude-code`,
MANUAL_REDIRECT_URL: `${consoleBase}/oauth/code/callback`,
CLIENT_ID: '22422756-60c9-4084-8eb7-27705fd5cf9a',
OAUTH_FILE_SUFFIX: '-local-oauth',
MCP_PROXY_URL: 'http://localhost:8205',
MCP_PROXY_PATH: '/v1/toolbox/shttp/mcp/{server_id}',
}
}
// Allowed base URLs for CLAUDE_CODE_CUSTOM_OAUTH_URL override.
// Only FedStart/PubSec deployments are permitted to prevent OAuth tokens
// from being sent to arbitrary endpoints.
const ALLOWED_OAUTH_BASE_URLS = [
'https://beacon.claude-ai.staging.ant.dev',
'https://claude.fedstart.com',
'https://claude-staging.fedstart.com',
]
// Default to prod config, override with test/staging if enabled
export function getOauthConfig(): OauthConfig {
let config: OauthConfig = (() => {
switch (getOauthConfigType()) {
case 'local':
return getLocalOauthConfig()
case 'staging':
return STAGING_OAUTH_CONFIG ?? PROD_OAUTH_CONFIG
case 'prod':
return PROD_OAUTH_CONFIG
}
})()
// Allow overriding all OAuth URLs to point to an approved FedStart deployment.
// Only allowlisted base URLs are accepted to prevent credential leakage.
const oauthBaseUrl = process.env.CLAUDE_CODE_CUSTOM_OAUTH_URL
if (oauthBaseUrl) {
const base = oauthBaseUrl.replace(/\/$/, '')
if (!ALLOWED_OAUTH_BASE_URLS.includes(base)) {
throw new Error(
'CLAUDE_CODE_CUSTOM_OAUTH_URL is not an approved endpoint.',
)
}
config = {
...config,
BASE_API_URL: base,
CONSOLE_AUTHORIZE_URL: `${base}/oauth/authorize`,
CLAUDE_AI_AUTHORIZE_URL: `${base}/oauth/authorize`,
CLAUDE_AI_ORIGIN: base,
TOKEN_URL: `${base}/v1/oauth/token`,
API_KEY_URL: `${base}/api/oauth/claude_cli/create_api_key`,
ROLES_URL: `${base}/api/oauth/claude_cli/roles`,
CONSOLE_SUCCESS_URL: `${base}/oauth/code/success?app=claude-code`,
CLAUDEAI_SUCCESS_URL: `${base}/oauth/code/success?app=claude-code`,
MANUAL_REDIRECT_URL: `${base}/oauth/code/callback`,
OAUTH_FILE_SUFFIX: '-custom-oauth',
}
}
// Allow CLIENT_ID override via environment variable (e.g., for Xcode integration)
const clientIdOverride = process.env.CLAUDE_CODE_OAUTH_CLIENT_ID
if (clientIdOverride) {
config = {
...config,
CLIENT_ID: clientIdOverride,
}
}
return config
}