跳转至

Deep Dive | src/services/mcp/auth.ts 2465 行 — MCP OAuth 鉴权完整实现

重要性:⭐⭐⭐⭐(MCP 鉴权核心——OAuth 2.0 + PKCE + Step-up + XaaS) 真实位置src/services/mcp/auth.ts2465 行角色:MCP 协议 OAuth 2.0 鉴权完整实现——授权码、PKCE、refresh token、step-up 检测、XaaS 身份提供商 关联topics/deep-dive-mcp-client.mdtopics/mcp-protocol-deep-dive.md


1. 文件全景

mcp/auth.ts (2465 行)
├── 行 1-160  :imports + 类型 + 常量
│   ├── AUTH_REQUEST_TIMEOUT_MS (30s)
│   ├── MCPRefreshFailureReason (行 71)
│   ├── MCPOAuthFlowErrorReason (行 84)
│   ├── MAX_LOCK_RETRIES (5)
│   ├── SENSITIVE_OAUTH_PARAMS (行 100, 12 项)
│   ├── redactSensitiveUrlParams (行 112, ~35 行)
│   ├── NONSTANDARD_INVALID_GRANT_ALIASES (行 147)
│   └── normalizeOAuthErrorBody (行 157, ~40 行)
├── 行 198-310:fetch + discovery
│   ├── createAuthFetch (行 198, ~58 行)
│   └── fetchAuthServerMetadata (行 256, ~57 行)
├── 行 313-350:错误类 + 工具
│   ├── AuthenticationCancelledError (行 313)
│   ├── getServerKey (行 325, ~25 行)
│   └── hasMcpDiscoveryButNoToken (行 349, ~32 行)
├── 行 381-635:token 管理
│   ├── revokeToken (行 381, ~85 行)
│   ├── revokeServerTokens (行 467, ~150 行)
│   └── clearServerTokensFromLocalStorage (行 620, ~16 行)
├── 行 636-846:XaaS
│   ├── WWWAuthenticateParams type
│   ├── XaaFailureStage type
│   └── performMCPXaaAuth (行 664, ~180 行)
├── 行 847-1354:**performMCPOAuthFlow (行 847, ~500 行)** — OAuth 主流程
├── 行 1354-1376:wrapFetchWithStepUpDetection
├── 行 1376-2360:**ClaudeAuthProvider (行 1376, ~985 行)** — OAuth provider 实现
└── 行 2360-2465:client secret 管理
    ├── readClientSecret (行 2362, ~37 行)
    ├── saveMcpClientSecret (行 2399, ~17 行)
    ├── clearMcpClientConfig (行 2416, ~14 行)
    ├── getMcpClientConfig (行 2430, ~15 行)
    └── getScopeFromMetadata (行 2445)

2. 核心常量

2.1 AUTH_REQUEST_TIMEOUT_MS = 30000

30s auth 请求超时——OAuth 流程不能挂起。

2.2 MAX_LOCK_RETRIES = 5

5 次 lock 重试——并发 OAuth 流程冲突。

2.3 SENSITIVE_OAUTH_PARAMS — 12 项敏感参数

const SENSITIVE_OAUTH_PARAMS = [
  'client_secret', 'access_token', 'refresh_token', 'id_token', 
  'code', 'state', 'code_verifier', 'assertion', 'signature',
  // ...
]

12 个 —— 错误信息中必须 redact

2.4 NONSTANDARD_INVALID_GRANT_ALIASES

const NONSTANDARD_INVALID_GRANT_ALIASES = new Set([
  'invalid_grant', 'invalid_token', 'access_denied', ...
])

兼容老 OAuth server 的错误名变体。


3. redactSensitiveUrlParams — 35 行(行 112)

function redactSensitiveUrlParams(url: string): string {
  // https://x.com/?code=abc&state=xyz → https://x.com/?code=***&state=***
}

URL 凭证脱敏——错误信息保护。


4. normalizeOAuthErrorBody — 40 行(行 157)

export async function normalizeOAuthErrorBody(response, serverName): Promise<...> {
  // 统一 OAuth 错误格式
}

错误标准化——不同 server 错误格式不同,统一。


5. createAuthFetch — 58 行(行 198)

function createAuthFetch(): FetchLike {
  // fetch with 30s timeout
}

30s fetch wrapper——OAuth HTTP 请求超时。


6. fetchAuthServerMetadata — 57 行(行 256)

async function fetchAuthServerMetadata(serverUrl): Promise<...> {
  // 1. 尝试 /.well-known/oauth-authorization-server
  // 2. 尝试 RFC 8414 endpoint
  // 3. 解析 metadata
}

OAuth discovery —— 按 RFC 8414 获取 authorization / token endpoint。


7. AuthenticationCancelledError(行 313)

export class AuthenticationCancelledError extends Error { ... }

用户取消——特殊错误类型。


8. getServerKey + hasMcpDiscoveryButNoToken(行 325, 349)

getServerKey(serverName)  // 服务标识
hasMcpDiscoveryButNoToken(server)  // 检查是否需要重新认证

2 个 helper


9. revokeToken + revokeServerTokens(行 381, 467)

async function revokeToken(...) { ... }  // 单 token 撤销
async function revokeServerTokens(...) { ... }  // 服务器所有 token 撤销

2 个 token 撤销——按 RFC 7009。


10. performMCPXaaAuth — 180 行(行 664)

async function performMCPXaaAuth(server, ...): Promise<...> {
  // XaaS (External-as-a-Service) 身份提供商
}

XaaS —— 第三方身份提供商(Auth0、Okta、Azure AD 等)。


11. performMCPOAuthFlow — 500 行核心(行 847-1354)

export async function performMCPOAuthFlow(server, ...): Promise<...> {
  // 1. discovery
  // 2. 动态 client registration (如果需要)
  // 3. 生成 PKCE code_verifier + code_challenge
  // 4. 打开浏览器 → 授权
  // 5. 等待 callback
  // 6. 交换 code → token
  // 7. 存储 token
  // 8. 返回 token
}

500 行 —— 完整 OAuth 2.0 Authorization Code + PKCE 流程。

关键步骤: 1. Discovery —— 找 auth / token endpoint 2. Dynamic Client Registration —— 如果 server 不认识 client 3. PKCE —— 防截持 4. Browser open —— 用户登录 5. Callback listener —— 等待 redirect 6. Token exchange —— code → access_token + refresh_token 7. Storage —— 加密存储


12. wrapFetchWithStepUpDetection

export function wrapFetchWithStepUpDetection(fetch, ...): FetchLike {
  // 检测 401 → 触发 step-up auth
}

Step-up 鉴权 —— 当 server 返回 401 时,触发重新认证。


13. ClaudeAuthProvider — 985 行(行 1376-2360)

export class ClaudeAuthProvider implements OAuthClientProvider {
  // ~985 行
  // 实现 OAuthClientProvider 接口
}

985 行 —— MCP SDK 的 OAuthClientProvider 实现。

包括: - getClientMetadata() —— client 信息 - clientInformation() —— 动态注册结果 - tokens() —— 当前 token - saveTokens() —— 存储 - redirectToAuthorization() —— 打开浏览器 - saveCodeVerifier() —— PKCE - codeVerifier() —— 读取 verifier - invalidateCredentials() —— 撤销 - prepareResourceServer() —— 资源服务器 - fetchAuthServerMetadata() —— discovery - ... 20+ 方法

985 行反映 OAuth client provider 的复杂(PKCE、动态注册、step-up、token 刷新等)。


14. Client Secret 管理(5 个函数)

readClientSecret()         // 读(环境变量或 keychain)
saveMcpClientSecret()      // 写
clearMcpClientConfig()     // 清
getMcpClientConfig()       // 读
getScopeFromMetadata()     // 从 metadata 解析 scope

5 个函数 —— 客户端凭证的存储 / 检索。


15. 关键设计模式

15.1 OAuth 2.0 完整实现

Authorization Code + PKCE —— 标准 OAuth 2.0 flow。

15.2 Dynamic Client Registration

如果 server 不认识 client —— 自动注册

15.3 PKCE 强制

所有流程都带 PKCE —— 防截持

15.4 Step-up 鉴权

wrapFetchWithStepUpDetection —— 401 时自动重新认证

15.5 错误标准化

normalizeOAuthErrorBody —— 不同 server 错误格式统一。

15.6 凭证脱敏

redactSensitiveUrlParams + SENSITIVE_OAUTH_PARAMS —— 错误信息保护。

15.7 Lock 重试

MAX_LOCK_RETRIES = 5 —— 并发 OAuth 流程冲突重试

15.8 30s timeout

AUTH_REQUEST_TIMEOUT_MS —— 防止挂起。

15.9 XaaS 支持

performMCPXaaAuth —— 第三方 IdP(Auth0、Okta)。

15.10 Token 撤销

revokeToken / revokeServerTokens —— 按 RFC 7009 撤销。

15.11 985 行 ClaudeAuthProvider

最大单 class —— 实现完整 OAuth client。


16. 复杂度分析

维度 数字
总行数 2465
公开函数 15+
错误类 2
核心流程 performMCPOAuthFlow 500 行
Provider class 985 行
敏感参数 12

17. 性能特征

17.1 首次 OAuth

  • Discovery:~100ms-1s
  • Browser open:~5-30s(用户登录)
  • Token exchange:~100-500ms
  • 总计 ~5-30s

17.2 Token 刷新

  • Refresh:~100-500ms
  • 通常透明(user 不感知)

17.3 Step-up

  • 401 → 重新 OAuth:~5-30s
  • 罕见(通常只首次 + 过期)

18. 与其他文件的关系

mcp/auth.ts
  ├──→ @modelcontextprotocol/sdk (OAuthClientProvider 接口)
  ├──→ local storage (token 存储)
  ├──→ keychain (client secret)
  ├──→ browser (openExternal)
  └──→ mcp/client.ts (用 ClaudeAuthProvider)

19. 关键洞察

19.1 OAuth 完整实现是"大工程"

500 + 985 = 1485 行 —— OAuth 完整实现很复杂

19.2 PKCE 强制是"现代最佳实践"

OAuth 2.1 推荐 PKCE —— 不要 client_secret

19.3 Step-up 是"用户体验"

不用用户手动重新登录 —— 401 自动重试。

19.4 凭证脱敏是"安全细节"

SENSITIVE_OAUTH_PARAMS —— 错误信息保护。

19.5 错误标准化是"兼容性"

不同 server 错误格式统一 —— 用户看到一致错误。

19.6 985 行 ClaudeAuthProvider

单 class 单职责 —— 实现完整 OAuth client。

19.7 XaaS 支持

第三方 IdP —— 企业友好

19.8 30s timeout 防止挂起

OAuth 不能挂死 —— 必须有上限。


20. 阅读建议

  1. 看 SENSITIVE_OAUTH_PARAMS(行 100)—— 12 项
  2. 看 performMCPOAuthFlow 500 行(行 847)
  3. 看 ClaudeAuthProvider 985 行(行 1376)
  4. 看 wrapFetchWithStepUpDetection(行 1354)—— 401 检测

21. 与其他深度拆解的关系

文件 关系
mcp/client.ts 用 ClaudeAuthProvider
mcp/types.ts OAuth type
auth.ts (utils) 通用 auth

22. 阅读清单

  1. ✅ 看 SENSITIVE_OAUTH_PARAMS(行 100)
  2. ✅ 看 performMCPOAuthFlow(行 847)
  3. ✅ 看 ClaudeAuthProvider(行 1376)
  4. 📌 对照 topics/deep-dive-mcp-client.md

23. 练习任务

  1. 数 OAuth 流程步骤(grep)—— 8+ 步
  2. 数 ClaudeAuthProvider 方法(grep)—— 20+
  3. 画 OAuth 流程图 —— discovery → PKCE → authorize → token
  4. 手写迷你 OAuth client(~100 行)—— PKCE + token exchange
  5. 思考:OAuth 流程最容易出错的是哪一步?