Skip to content

[Feature]: Allow re-authentication / replacement of an expired pool account instead of blocking with "Account is already in the pool" #4066

Closed

Description

@nordz0r

Area

Authentication and account pool

What are you trying to accomplish?

Re-authenticate a Codex pool account that has expired or dropped its session (e.g., token revoked, session expired), so that the account becomes usable again without having to delete it from the pool first.

What prevents this today?

When a pool account expires and the operator tries to log in again via the WebUI (or CLI) using the same account credentials, checkAccountIdCollision (src/codex/auth-collision.ts) sees that the chatgptAccountId already exists in the pool config and rejects the login attempt with:

Account is already in the pool (chatgpt-...)

The only workaround today is a destructive 2-step process:

  1. Delete the expired account from the pool.
  2. Re-add it via a fresh login.

This destroys the account's usage history, quota recovery state, manually configured priority/strategy settings, and pool labels.

What should OpenCodex do?

When a login flow completes and checkAccountIdCollision detects that the account already exists in the pool, it should check if the existing pool account's session is expired, invalid, or being explicitly re-authenticated. Instead of aborting the flow with a collision error, OpenCodex should update the existing account in-place with the new credential/tokens, preserving its id, usage history, and configuration.

If an operator explicitly clicks "Re-authenticate" (or runs an equivalent CLI command), the collision check should be bypassed entirely for that specific account ID, or the merge logic should just overwrite the token material.

Example usage or interface

  1. Dashboard shows a pool account as Expired / Needs re-authentication.
  2. Operator clicks "Re-authenticate" on that account card.
  3. OAuth/Device flow completes.
  4. Instead of Account is already in the pool error, the UI says Account re-authenticated successfully and the token is updated. History and routing settings remain intact.

Alternatives or workarounds

  • Deleting the account and re-adding it — loses all historical usage data, manual aliases, and pool configuration.
  • Manually editing auth.json / config.json on the filesystem — error-prone and defeats the purpose of the management API.

Additional context

Checks

  • I searched existing issues and documentation.
  • This request describes a concrete OpenCodex workflow rather than merely naming a desired technology.
  • I removed secrets and personal data.

Activity

  1. lidge-jun commented on Sep 8, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 34 / 80

    설명

    이 이슈는 Codex 풀 계정이 만료·세션 끊김으로 못 쓰일 때, 같은 ChatGPT 계정으로 다시 로그인하면 checkAccountIdCollision이 “Account is already in the pool”로 막고, 그래서 풀에서 지운 뒤 다시 넣어야 해서 사용 기록·우선순위·라벨이 사라진다는 요청입니다. 작성자 nordz0r, 라벨은 enhancement + account-pool입니다. 관련로 본문이 적은 #3375(풀 라이프사이클)·#3846(등록이 warmup 성공에 묶임)은 아직 열려 있고, 비슷한 축의 #3898은 네이티브 main(__main__)을 headless 허브 WebUI에서 reauth하는 별 문제라 이 이슈와 같지 않습니다. 지금 로컬 dev HEAD는 8026405d9(#4067 wp7 프록시 stop 거절 사유), package 2.49.0입니다. types.ts/config.ts 분할·preview 배포와는 무관합니다. 이 번호로 열린 구현 PR은 없습니다.

    왜 우선순위가 낮은가. 요청한 “제자리 재인증”은 이미 현재 dev에 들어가 있습니다. 새 계정 추가 경로만 보면 본문 설명이 맞습니다. src/codex/auth-collision.ts의 checkAccountIdCollision은 같은 개인/워크스페이스 버킷 안에서 같은 chatgptAccountId(그리고 이메일이 있으면 같은 이메일)를 보면 충돌로 끝냅니다. 그런데 네 번째 인자 excludeAccountId가 있고, 재인증일 때는 그 슬롯을 건너뜁니다. src/codex/auth-api.ts의 POST /api/codex-auth/login은 body에 reauth: true와 풀 id가 오면 재인증 모드로 갑니다. 같은 ChatGPT 정체인지 확인한 뒤, 충돌 검사에서 그 id를 빼고, 자격 증명을 그 풀 id 위에 덮어씁니다. 성공하면 clearAccountNeedsReauth로 격리도 풉니다. 풀 행 id는 그대로라서, 본문이 걱정한 “지우고 다시 넣기”로 히스토리가 날아가는 경로를 피할 수 있게 이미 설계되어 있습니다.

    화면과 CLI도 같은 길을 씁니다. GUI gui/src/components/CodexAccountPool.tsx는 openReauth(id)로 모달을 열고, gui/src/components/use-add-codex-account-oauth.ts가 { id, reauth: true }로 로그인 API를 호출합니다. 카드/배너의 “Re-authenticate” 버튼(codex-account-pool-cards.tsx)이 그 진입점입니다. CLI는 ocx account login … --reauth / ocx account reauth(src/cli/account-auth.ts)입니다. 그래서 운영자가 추가(Add) 흐름으로 같은 계정을 또 넣으려 하면 충돌 문구가 뜨는 것이 맞고, 재인증(Re-authenticate) 흐름을 쓰면 본문이 그린 목표(토큰만 갱신, 풀 id·설정 유지)에 가깝게 동작합니다. 2.49.0 마감 트레인(#4067 직후)에서 새로 큰 기능을 열 이슈가 아니라, “이미 있는 길을 못 찾은 요청”에 가깝습니다.

    남는 구멍은 작습니다. (1) 추가 흐름의 충돌 메시지가 “재인증 버튼을 쓰라”고 안내하지 않아, 본문처럼 삭제 우회로만 떠올릴 수 있습니다. (2) 재인증인데 풀에 chatgptAccountId도 이메일도 없으면 auth-api.ts가 “Cannot verify account identity for reauth”로 거절합니다. 빈 슬롯·깨진 자격은 의도적으로 조용히 덮어쓰지 않습니다. (3) 로그인 성공 후 warmup이 실패하면 #3846처럼 등록/갱신이 막힐 수 있어, “재인증 버튼은 눌렀는데 실패”로 느껴질 수 있습니다. 그건 이 이슈의 collision 하드블록과는 다른 버그 축입니다. (4) #3898 headless native main reauth는 풀 계정 CTA로는 안 풀립니다.

    src/codex/auth-collision.ts checkAccountIdCollision - 네 번째 excludeAccountId로 재인증 슬롯을 건너뛴다. “이미 풀에 있음”은 신규 추가에만 해당하는 가드다.
    src/codex/auth-api.ts POST /api/codex-auth/login reauth - id 필수, 풀에 없는 id면 404. 같은 ChatGPT id(또는 이메일이 있을 때 이메일)만 허용한 뒤 자격만 덮어쓴다.
    src/codex/auth-api.ts 정체 확인 실패 분기 - id·이메일이 둘 다 없으면 재인증 거절. 잘못된 계정으로 슬롯을 바꾸는 사고를 막는다.
    gui/.../use-add-codex-account-oauth.ts - 재인증 때 { id, reauth: true }와 login-status reauth=1. Add와 경로가 갈라진다.
    gui/.../codex-account-pool-cards.tsx / CodexAccountPool.tsx - needs-reauth 카드·배너에 Re-authenticate CTA가 있다.
    src/cli/account-auth.ts - ocx account reauth / --reauth가 같은 API를 탄다.
    경로 Account is already in the pool 문구 - 신규 충돌에만 나오고, 재인증 안내 문장은 없다. 발견성(UX/카피) 문제이지, API 부재는 아니다.

    메인테이너의 판단이 필요한 지점

    너의 추천
    닫으세요(이미 dev에 재인증 경로 있음). 작성자에게는 Providers Codex 풀 카드의 Re-authenticate, 또는 ocx account reauth --id <pool-id>를 안내하면 됩니다. “Add account”로 같은 ChatGPT를 또 넣으면 충돌이 정상입니다. 만약 Re-authenticate를 썼는데도 막혔다면, 그 오류 문구·warmup 실패·headless main 여부를 새 댓글/이슈로 쪼개 주세요(#3846·#3898과 섞지 말 것). types/config 분할 무관, close-don't-rebase 대상 아님. 충돌 메시지에 재인증 안내를 넣고 싶으면 별도 초소형 PR만 받으면 됩니다.

    이 댓글은 grok-bot이 작성했습니다

  2. lidge-jun commented on Sep 9, 2026

    @lidge-jun
    Owner

    Thanks for the detailed write-up. The in-place re-authentication you describe already ships on dev (8026405) — it is just on a different entry point from Add account.

    checkAccountIdCollision takes a fourth excludeAccountId argument (src/codex/auth-collision.ts:94,99), and POST /api/codex-auth/login passes the target pool id when reauth: true is set (src/codex/auth-api.ts:2629-2632,2751), so the collision check skips that slot and only the credential is overwritten. The pool id is kept stable and the re-auth quarantine is cleared on success (src/codex/auth-api.ts:2803-2807), so usage history, alias, and routing settings survive.

    In the dashboard, use the Re-authenticate action on the account card (gui/src/components/CodexAccountPool.tsx:189); from the CLI, run ocx account reauth --id <pool-id> (src/cli/account-auth.ts:282). The collision error is the correct answer for Add account, because that path must not silently replace a different account's credential.

    Closing as already supported. If you did use Re-authenticate and it still failed, please open a new report with the exact error text — that would be a different defect (warmup coupling is tracked in #3846, headless native-main recovery in #3898).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    account-poolOAuth, credentials, Codex pool, quota, failover, plansenhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions