Skip to content

[Bug] 계정 목록 API/대시보드가 __main__ 계정의 무효 상태를 표시하지 않음 (needsReauth 미노출) #327

Closed

Description

@jhste102lab

Client or integration

Codex CLI

Area

Authentication and account pool

Summary

__main__(native ~/.codex/auth.json) 계정의 자격증명이 무효가 되어도 관리 API와 대시보드가 그 사실을 전혀 표시하지 않습니다. pool 계정은 needsReauth 필드로 상태를 알 수 있지만, __main__은 해당 필드 자체가 DTO에 없고 실패 시 plan: null, quota: null만 남습니다. 이 값은 "아직 quota prime이 안 된 정상 계정"과 구분되지 않습니다.

codexAccountMode: pool에서 __main__은 rotation에 참여하므로(codex/routing.ts:256-262), 무효한 main이 선택되면 요청이 upstream 403으로 실패합니다. 그런데 대시보드에는 아무 이상 신호가 없어서 원인을 찾기가 어렵습니다.

기대 동작: __main__도 pool 계정과 동일하게 헬스 상태(needsReauth 또는 이에 준하는 오류 표시)를 노출해야 합니다.

Reproduction

  1. ~/.codex/auth.json을 무효한 ChatGPT 토큰으로 만듭니다. (재현에 사용한 상태: 토큰에 박힌 workspace가 더 이상 선택 불가여서 upstream이 403 {"detail":{"code":"invalid_workspace_selected"}}를 반환, refresh token도 401 invalid_refresh_token)
  2. pool에는 정상 OAuth 계정을 여러 개 등록해 둡니다.
  3. curl -s http://127.0.0.1:10100/api/codex-auth/accounts 를 호출합니다.
  4. 결과에서 __main__ 항목이 아래처럼 나옵니다. pool 계정에는 needsReauth: false가 있지만 __main__에는 상태를 나타내는 필드가 없습니다.
{ "id": "__main__", "email": "Codex App login", "plan": null,
  "isMain": true, "hasCredential": true, "quota": null }
  1. ?refresh=1을 붙여 강제 갱신해도 동일합니다. 대시보드에서도 main 계정은 정상 항목과 동일하게 보입니다.

관련 코드 두 곳으로 보입니다.

  • src/codex/auth-api.ts listCodexAuthAccounts() — main DTO를 만들 때 needsReauth를 넣지 않습니다. pool 쪽 poolAccountDto()에는 포함됩니다.
  • src/codex/auth-api.ts fetchMainAccountInfo() — if (!resp.ok) return { email: null, plan: null, quota: null } 로 처리해서, wham/usage가 돌려준 401/403(= 자격증명이 죽었다는 강한 신호)을 그대로 버립니다. 이 시점에 markAccountNeedsReauth(MAIN_CODEX_ACCOUNT_ID)를 하지 않습니다.

isCodexAccountUsable()와 routing.ts는 이미 isAccountNeedsReauth(MAIN_CODEX_ACCOUNT_ID)를 확인하고 있어서, 상태를 세팅·노출하는 경로만 보완되면 기존 rotation 로직과 자연스럽게 맞물릴 것으로 보입니다.

제안:

  • fetchMainAccountInfo()에서 401/403이면 markAccountNeedsReauth(MAIN_CODEX_ACCOUNT_ID) 호출
  • main DTO에도 needsReauth(또는 마지막 실패 상태) 필드 추가

Version

  • @bitkyc08/opencodex: 2.7.33
  • @openai/codex: 0.145.0

Operating system

Ubuntu 24.04.4 LTS (x86_64, WSL2) — 동일 증상을 Ubuntu 서버 3대, Oracle Linux aarch64 1대에서도 확인

Provider and model

  • Provider: openai (ChatGPT 백엔드, authMode: forward)
  • Model: gpt-5.5, gpt-5.6-terra

Logs or error output

# 1) main 토큰으로 upstream 직접 호출
$ POST https://chatgpt.com/backend-api/codex/responses
403 {"detail":{"code":"invalid_workspace_selected"}}

# 2) main refresh token
$ POST https://auth.openai.com/oauth/token (grant_type=refresh_token)
401 {"error":{"code":"invalid_refresh_token","message":"Invalid refresh token."}}

# 3) 같은 시점 관리 API — main 계정에 이상 신호 없음
$ curl -s http://127.0.0.1:10100/api/codex-auth/accounts
[('__main__',  '<masked>', None,   None),
 ('<pool-1>',  '<masked>', 'team', False),
 ('<pool-2>',  '<masked>', 'team', False),
 ('<pool-3>',  '<masked>', 'team', False)]
   # 튜플 = (id, email, plan, needsReauth)
   # 계정 id/email은 마스킹했습니다. 핵심은 pool 계정에는 needsReauth가 있고
   # __main__에는 그 자리에 아무 상태 필드도 없다는 점입니다.

참고

#320 과 주제는 인접하지만 다른 지점이라고 생각합니다. #320은 native auth가 만료됐을 때 Codex CLI가 로그인창을 여는 동작에 대한 것이고, 이 이슈는 OpenCodex 자신의 계정 목록 API/대시보드가 __main__의 무효 상태를 표시하지 않는다는 관측성 문제입니다. 중복이라고 판단되시면 닫아주셔도 괜찮습니다.

Activity

  1. Ingwannu commented on Jul 23, 2026

    @Ingwannu
    Owner

    최신 dev (92d9a9e2)에서 확인했으며 실제 버그가 맞습니다.

    현재 코드에서도:

    • fetchMainAccountInfo()가 wham/usage의 모든 non-2xx를 { email: null, plan: null, quota: null }로 축약해 인증 실패 정보를 버립니다.
    • listCodexAuthAccounts()의 __main__ DTO에는 needsReauth가 없으며 hasCredential: true도 고정값입니다.
    • 반면 pool DTO에는 needsReauth가 있고, 라우팅 경로는 이미 isAccountNeedsReauth("__main__")를 검사합니다.

    따라서 무효한 main 계정이 정상/미확인 계정처럼 표시되고 rotation 후보에 남을 수 있다는 분석이 코드와 일치합니다.

    수정할 때는 main 조회 결과에 인증 상태를 포함하고 DTO에도 needsReauth를 노출하되, 일반적인 403을 전부 영구 재인증 상태로 만들지는 않아야 합니다. 401, refresh-token의 terminal failure, 또는 invalid_workspace_selected처럼 확정적인 인증 오류만 mark하고 성공적인 재인증/조회 시 clear하는 방향으로 처리하는 것이 안전합니다. 해당 케이스의 회귀 테스트도 함께 필요합니다.

  2. added a commit that references this issue on Jul 23, 2026
    0479e04
  3. Ingwannu commented on Jul 23, 2026

    @Ingwannu
    Owner

    최신 dev의 0479e046에서 수정했습니다.

    변경 내용:

    • __main__ DTO의 hasCredential을 실제 native auth 파일 존재 여부로 계산
    • credential 없음, HTTP 401, allowlist된 structured 403(invalid_workspace_selected, invalid_refresh_token)을 needsReauth로 표시
    • 일반적인 403/네트워크 오류는 terminal auth failure로 오판하지 않음
    • 성공적인 main usage refresh에서 runtime reauth 상태를 해제
    • terminal failure에서는 이전 main quota cache도 무효화
    • 오류 본문은 bounded reader로 읽고 allowlist code만 사용하며 본문/토큰을 기록하지 않음

    검증:

    • main 401, invalid-workspace 403, 일반 403, 성공 복구 회귀 테스트 통과
    • 전체 로컬 테스트 3,706개 통과, 실패 0개
    • Linux/macOS/Windows cross-platform CI 전체 통과

    완료 처리합니다.

  4. added a commit that references this issue on Aug 20, 2026
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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions