Skip to content

修正 Claude 登录失效后的账号判断与提示 - #716

Merged
yetone merged 3 commits into
yetone:mainfrom
Koohoko:codex/claude-login-status
Oct 3, 2026
Merged

yetone merged 3 commits into
yetone:mainfrom
Koohoko:codex/claude-login-status

Conversation

@Koohoko

@Koohoko Koohoko commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Claude Code 返回 OAuth session expired and could not be refreshed 后,magpie 仍把账号当作临时故障,显示“正在休息”并继续重试。连接测试成功时也没有注明测试的账号,容易让用户误以为所有账号都正常。

多账号用户需要 magpie 跳过失效登录、继续使用其他账号,并明确说明哪些账号需要重新登录;凭据恢复后,也应该自动恢复使用。

本 PR:

  • 按当前凭据判断是否可用:被拒绝的旧凭据不再运行;检测到新凭据后恢复使用,避免临时读取失败导致账号一直被标为失效。
  • 统一使用和切换账号时的判断:不把已被拒绝或清空的旧凭据写回 Claude Code。
  • 准确处理和展示失效状态:取消这类失败的休息倒计时,转给其他账号;全部失效时提示重新登录。保留原始错误,提供重新登录入口,并在连接测试结果中注明实际测试的账号。

OAuth 续期仍由 Claude Code 负责,本 PR 修正 magpie 对登录失效的判断和处理。

验证:全量 Go 测试、相关 race 检查、三平台构建及 16 项中英文浏览器测试通过。测试使用模拟凭据,尚未用真实失效账号做端到端验证。

关联 #53、#524。


🎬 界面预览

CI 用这个 PR 的代码构建并真实运行 magpie(沙盒环境,配置了真实的 DeepSeek key),按改动自动操作、截图和录屏 · eceedde · 运行记录

改动(按代码):Claude 账号登录被 Anthropic 拒绝时,供应商页的账号行改为显示「需要重新登录」、禁用启用开关并提供「重新登录」按钮(不再计入可用账号、不再让位给暂停/设为首选),路由页为这类失败新增「需要重新登录」的说法与说明文案,连接测试结果会注明所测账号。

Note

沙盒里看不到:沙盒只有 DeepSeek 一个供应商,没有任何 Claude/Codex 订阅账号,也没有失效登录的数据:供应商页里的 Claude 账号行(「需要重新登录」标签、被禁用的圆点、「重新登录」/「移除」按钮)、连接测试结果里的「已测试 {user}:…」前缀、以及路由页请求步骤中的认证失败说明,都不会出现——路由页只有成功的 DeepSeek 请求,所以只能看到这些改动所在的位置。

播放录屏

▶️ 点图打开录屏(可暂停、拖动)· 直接下载 mp4 · 红线是鼠标轨迹,红色圆环是点击

供应商页:账号行与连接测试的位置

供应商列表:这个沙盒里只有 DeepSeek,没有带账号的 Claude Code 供应商

供应商列表:这个沙盒里只有 DeepSeek,没有带账号的 Claude Code 供应商

「测试」的结果行显示在这里(此处没有订阅账号可注明)

「测试」的结果行显示在这里(此处没有订阅账号可注明)

路由页:失败说明出现的位置

路由页的请求步骤列表:认证失败的说明会出现在这里

路由页的请求步骤列表:认证失败的说明会出现在这里

这条请求的路由步骤

这条请求的路由步骤

⚠️ 有 1 步没能照计划执行
  • 路由页:失败说明出现的位置 · shot .rt-log: nothing visible matches .rt-log (1 in the page)

A refusal is kept for the credential it was made on (savedLogin.Refused)
and holds only while the account still has that credential. One check,
claudeSignedOut, decides whether a saved Claude login can be used, after
syncClaudeDir has read what Claude Code keeps in the account's directory:
a credential it refreshed to there is taken, and one it emptied (as
Claude Code 2.1.x does after Anthropic answers invalid_grant) is refused.
Token is the only gate: a saved account's directory, or the credential
Claude Code itself holds for its own account. Lapsed accounts stay
candidates, so the trace shows each one passed over and the agent is told
to sign in again when none is left.

This fixes four paths of the first version: a moment the own sign-in
could not be read left it lapsed after it came back unchanged; a
credential refreshed in the account's directory after a refusal was
ignored; a switch could restore a copy Claude Code had emptied; and with
every account refused the agent got "none of ... is ready" (404).
@Koohoko
Koohoko deployed to ui-preview October 3, 2026 19:58 — with GitHub Actions Active
github-actions Bot added a commit that referenced this pull request Oct 3, 2026
@yetone

yetone commented Oct 3, 2026

Copy link
Copy Markdown
Owner

感谢这个 PR!核心思路(按凭据版本记录拒绝、Claude Code 清空凭据后不再写回、刷新/重新登录后自动恢复)我在沙盒里验证过,go vet、三平台构建、go test ./... 和 claude-auth-status.test.cjs(webkit en/zh)都通过;也对照了 Claude Code 2.1.288 的实现:invalid_grant 时确实把 refreshToken/accessToken 置空,"OAuth session expired and could not be refreshed" 只在这种情况下出现,判断是对的。合并前请改以下几点:

  1. failAuth 只应作用于 Claude 账号:routing.go 的 failure() 对所有 provider 都用 ClaudeSignInRequired(body) 判断,gateway.go 新增的分支随后不休眠、直接跳过。其他 provider(例如用户自装的、走 Anthropic OAuth 的 OpenCode 插件)返回 "OAuth access token has been revoked" 时,不会被标记、也不再进入退避,之后每个请求都会先打到它;trace 里还写着"当前登录不再重试",并不属实。请在该分支(最好也在 failure() 里)加上 c.p.Account != nil && c.p.Account.Agent == "claude" 的限制。
  2. 账号列表的 lapsed 分支影响了所有订阅:renderAccounts 里新的 l.lapsed 分支(禁用勾选、显示"需要重新登录 / 重新登录 / 移除")对 Codex、插件、Qoder、Zed 等所有订阅都生效,超出了这个 PR 的范围;而且失效但仍开启的账号显示为未勾选、又无法取消勾选,后端却仍把它当作候选。请限定为 a.agent === "claude"(或说明并测试对其他订阅的改动)。另外,对 l.active 的行(Claude Code 仍登录着该账号)点"移除"会被 ForgetLogin 拒绝("switch to another account first"),这一行不应提供"移除"。
  3. i18n 缺漏:claudeGoneLapse("its sign-in is gone; sign in again")现在经过 t(l.lapsed) 显示,但 i18n.js 里没有对应的中文。
  4. 小建议:readOutput 里先判断 ClaudeSignInRequired(text) 再调用 ClaudeCodeMovedOff(),否则自身账号的每个错误结果都会多读一次钥匙串和 .claude.json;owner 的 "\x00" 拆分写了两处,可以提成一个小函数。

改完后我再拉下来跑一遍。

Address the review of yetone#716:

- A refused sign-in is failAuth only for a Claude account (failureOf);
  another vendor with the same words rests as before.
- The account list's sign-in-required row is Claude's only, and the
  account Claude Code is signed in to offers no Remove.
- Add the missing zh string for "its sign-in is gone; sign in again".
- readOutput checks the error before reading Claude Code's sign-in, and
  the owner is parsed in one place (ownerAccount).

TestSignInWordsFromAnotherVendorRest and the new browser case in
claude-auth-status.test.cjs fail on the previous commit and pass.
@Koohoko

Koohoko commented Oct 3, 2026

Copy link
Copy Markdown
Contributor Author

感谢细致的 review!已按这 4 点修改(eceedde):

  1. 新增 failureOf(c, …):只有 Claude 账号(c.p.Account.Agent == "claude")才判为 failAuth,failure() 不再识别这类文字。其他 provider 返回 "OAuth access token has been revoked" 时照旧退避。新增 TestSignInWordsFromAnotherVendorRest,旧代码下会失败。
  2. renderAccounts 的 lapsed 分支只对 a.agent === "claude" 生效,其他订阅保持原样;Claude Code 当前登录的账号不再显示「移除」。失效但仍开启的 Claude 账号仍是候选,但取凭据时直接报错并转给下一个账号,不会启动 Claude Code,也不进入退避。
  3. 补了 claudeGoneLapse 的中文。
  4. readOutput 先判断 ClaudeSignInRequired(text),再调用 ClaudeCodeMovedOff();owner 的拆分提成 ownerAccount(),三处共用。

验证:go vet、三平台构建、go test -tags nogui ./... 通过;claude-auth-status.test.cjs 新增一组用例(Codex 失效行不受影响、当前登录行无「移除」),chromium/webkit 中英文 8 项通过;账号相关的 13 个浏览器测试文件共 124 项通过。

@Koohoko
Koohoko deployed to ui-preview October 3, 2026 20:41 — with GitHub Actions Active
github-actions Bot added a commit that referenced this pull request Oct 3, 2026
@yetone
yetone merged commit dec9e70 into yetone:main Oct 3, 2026
8 checks passed
@yetone

yetone commented Oct 3, 2026

Copy link
Copy Markdown
Owner

已合并并随 v0.1.788 发布,感谢 @Koohoko!我把这 4 点修改拉下来合到当前 main 上跑了 go vet、三平台构建、全部 Go 测试,以及 claude-auth-status、account-*、keep-login 等 GUI 测试,都通过。

This branch was successfully deployed

1 active deployment
ui-preview — eceedde4 Deployed Oct 3, 2026 by Koohoko via record #447
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants