跳转到内容

认证系统的多策略架构

认证系统的多策略架构

学习目标

  • 理解 Codex 的 CodexAuth 枚举和 AuthProvider trait 抽象
  • 掌握 Codex 的 OAuth PKCE 流程和自动刷新机制
  • 分析 Codex 的 UnauthorizedRecovery 状态机和多账户安全

项目实践

认证架构

Codex 的认证系统分布在 codex-rs/login/src/auth/model-provider/

login/src/auth/
- manager.rs # AuthManager、CodexAuth 枚举
- api_key.rs # API Key 认证
- chatgpt.rs # OAuth (ChatGPT) 认证
- agent_identity.rs # JWT (Ed25519) 认证
- bearer.rs # Bearer token 通用实现
- recovery.rs # UnauthorizedRecovery 状态机
model-provider/src/
- provider.rs # ModelProvider trait(含 auth 方法)
- ...

CodexAuth 枚举

login/src/auth/manager.rs 定义了所有认证策略:

pub enum CodexAuth {
ApiKey(ApiKeyAuth),
Chatgpt(ChatgptAuth), // OAuth + refresh_token
ChatgptAuthTokens(ChatgptAuthTokens), // 外部传入的 token
AgentIdentity(AgentIdentityAuth), // JWT + Ed25519
}

统一转换auth_provider_from_auth()CodexAuth 转换为 SharedAuthProviderArc<dyn AuthProvider>),供 HTTP 客户端使用。

OAuth PKCE 流程

login/src/auth/chatgpt.rs 实现 ChatGPT OAuth:

pub struct ChatgptAuth {
pub access_token: String,
pub refresh_token: Option<String>,
pub expires_at: Option<DateTime<Utc>>,
pub account_id: String,
}

流程

  1. 生成 code_verifier + code_challenge(PKCE)
  2. 打开浏览器,用户授权
  3. 本地临时 HTTP 服务器接收 authorization_code
  4. 交换 access_token + refresh_token
  5. Token 过期前用 refresh_token 自动续期

Agent Identity (JWT + Ed25519)

login/src/auth/agent_identity.rs 实现服务间调用认证:

pub struct AgentIdentityAuth {
pub private_key: Ed25519PrivateKey,
pub key_id: String, // kid
}

签名流程

  1. 使用 Ed25519 私钥对请求进行签名
  2. 将 JWT(含 kid)放入 Authorization 头部
  3. 服务端使用对应的公钥验证签名

优势:无需与授权服务器交互,完全本地验证,适合高并发服务间调用。

AWS SigV4

model-provider/src/bedrock_mantle.rs 实现 AWS SigV4 签名:

impl BedrockMantleSigV4AuthProvider {
async fn sign_request(&self,
req: &mut Request,
) -> Result<> {
// 1. 剥离 Bedrock Mantle 不保留的 snake_case 头部
// 2. 使用 AWS SigV4 算法签名
// 3. 添加签名头部
}
}

关键细节:签名前剥离不保留的头部,避免签名失败。这是 AWS 生态集成的常见陷阱。

UnauthorizedRecovery 状态机

login/src/auth/recovery.rs 实现认证恢复:

pub struct UnauthorizedRecovery {
manager: Arc<AuthManager>,
step: UnauthorizedRecoveryStep,
expected_account_id: Option<String>,
mode: UnauthorizedRecoveryMode,
}
enum UnauthorizedRecoveryStep {
CheckRefreshToken,
RefreshToken,
Reauth,
Fail,
}

恢复流程

  1. 检查是否有 refresh_token
  2. 尝试刷新 access_token
  3. 如果刷新失败,进入交互式重新认证
  4. 验证 expected_account_id,防止账户切换攻击

问题与规避

Token 泄露风险

Codex 的缓解措施:

  • OAuth token 存储在系统 keyring 中(而非明文文件)
  • refresh_token 持久化时加密
  • 提供 logout 命令彻底清除认证状态

多账户切换

expected_account_id 防止攻击者通过刷新 token 切换到不同账户。如果刷新后的 token 属于不同账户,认证恢复失败。


设计取舍

枚举 vs trait 对象

Codex 在内部使用 CodexAuth 枚举,但对外暴露 Arc<dyn AuthProvider>。这种”内枚举外 trait”的设计:

  • 内部处理方便(模式匹配)
  • 对外扩展灵活(可添加新的 AuthProvider 实现)

本地存储 vs 系统 keyring

Codex 优先使用系统 keyring(macOS Keychain、Windows Credential Manager、Linux Secret Service)。当 keyring 不可用时回退到文件存储(加密后)。


参考来源