fix: accept RT-exchanged tokens missing chatgpt_account_id claim#674
fix: accept RT-exchanged tokens missing chatgpt_account_id claim#674xiaoliu10 wants to merge 1 commit into
Conversation
55bf4e7 to
1c17a34
Compare
icebear0828
left a comment
There was a problem hiding this comment.
Review
总体评价
修复方向正确,validateManualToken 对无 chatgpt_account_id 的 JWT 拒绝确实是兼容性问题。但存在两个 blocking 问题。
🔴 High
1. 缺少直接覆盖 bug 场景的测试(违反 TDD 规范)
所有测试用例均使用带 accountId 的 JWT,修复前也能通过。需补覆盖核心场景的用例:
it("accepts RT-exchanged token with no chatgpt_account_id claim", async () => {
const jwtWithoutAccountId = createValidJwt({ accountId: undefined });
const svc = new AccountImportService(pool, scheduler, makeDeps({
refreshToken: async () => ({ access_token: jwtWithoutAccountId, refresh_token: "new_rt" }),
}));
const result = await svc.importMany([{ refreshToken: "some_rt" }]);
expect(result.added).toBe(1);
expect(result.failed).toBe(0); // 老代码此处 failed=1
});2. addAccount 对 accountId = null 的账户去重失效
当 RT 兑换返回无 chatgpt_account_id 的 token 时,addAccount 去重键退化为 token 字符串本身。token 被 refresh 后内容改变,下次 addAccount 会创建重复条目,两个 entry 指向同一个 OpenAI 账户。
此 PR 让这类账户进入系统但未处理后续 token 刷新的去重,需要一并修复或明确标注 // KNOWN LIMITATION + 开 issue 追踪。
🟡 Medium
canAcceptRtExchangeToken 与 validateManualToken 大量逻辑重复
建议在 chatgpt-oauth.ts 提取 validateTokenStructure(token) 基础函数,两处共享,后续改动只需修改一处:
export function validateTokenStructure(token: string): { valid: boolean; error?: string } {
// 只做:非空 + 可解析 + 未过期
}
// validateManualToken 在此基础上加 accountId 检查rt as string 类型断言(L182/185/189/212)
项目规范禁止 as any,as string 同样是类型欺骗。在入口加显式 null guard:
if (!rt) return { ok: false, error: "Refresh token is required", kind: "validation" };🟢 Low
- 返回 token 前应统一
trim():token: tokens.access_token.trim() CHANGELOG.md [Unreleased]缺本次修复条目- L194 错误消息的
kind: "validation"语义不够精确,可考虑kind: "exchange_invalid"
结论
Request changes — 两个 High 问题(补 regression test + 修 null-accountId 去重)解决后可 approve。
|
感谢 PR!代码逻辑已经很完整了—— 唯一需要补充的:CHANGELOG 可以在 补好后可以 approve ✅ |
Summary
修复 Refresh Token 换取的 access token 缺少
chatgpt_account_idclaim 时导入失败的问题。OpenAI RT exchange 返回的 access token 有时不携带chatgpt_account_id,导致validateManualToken拒绝该 token,RT-only 导入无法完成。Changes
src/auth/jwt-utils.ts:新增extractCodexTokenMetadata()从 access_token + id_token 中提取 accountId / userId / email / planType,兼容 claim 在任一 token 中的情况src/services/account-import.ts:RT exchange 后用extractCodexTokenMetadata提取元数据传给 pool;新增canAcceptRtExchangeToken()允许缺少chatgpt_account_id但未过期的 RT 换取 token 通过验证;ImportDeps.refreshToken返回类型增加id_tokensrc/auth/account-registry.ts:addAccount()新增可选metadata参数,当extractChatGptAccountId返回 null 时回退到metadata.accountId,email/planType 同理src/auth/account-pool.ts:透传metadata参数到 registrysrc/auth/oauth-pkce.ts:refreshAccessToken返回类型增加id_token字段CHANGELOG.md:[Unreleased] → Fixed补充条目jwt-utils.test.ts补充extractCodexTokenMetadata用例;account-import.test.ts补充 RT exchange 缺 claim 场景;accounts-import-export.test.ts/rt-reuse-race.test.ts补齐extractCodexTokenMetadatamockTest Plan
npm test— 251 files, 2452 passed, 1 skippednpx tsc --noEmit— zero errors