Skip to content

Headless hub: WebUI cannot reauth native main (deviceauth is pool-only) #3898

Closed

Description

@nordz0r

Area

Dashboard / Authentication and account pool

What are you trying to accomplish?

Reauthenticate the native Codex App login (__main__, $CODEX_HOME/auth.json) from the OpenCodex WebUI on a headless hub (Docker/k3s, no local Codex App, oauthOpenBrowser: false).

This is not client pairing (ocx connect / pairing grant). Pairing only attaches a client to the hub. The native ChatGPT/Codex grant on the hub itself can become unusable for WHAM quota (token_revoked) even after a successful stored-token refresh, and an operator then needs a new device login that writes the native main slot — the same way pool rows already work after #3366/#3369/#3385.

What prevents this today?

On Codex Auth the main card is a locked App login identity. When reauth is needed it only shows codexAuth.mainTokenExpired ("Token expired — sign in again via Codex App login"). There is no Re-login / device-code control on that card (gui/src/components/codex-account-pool-main-card.tsx).

The WebUI device flow (POST /api/codex-auth/login with device: true) is pool-only:

  • { id: "__main__", reauth: true, device: true } → 400 Invalid account id format
  • { id: "main", reauth: true, device: true } → 404 Unknown pool account for reauth
  • { reauth: true, device: true } → 400 id required for reauth
  • { device: true } with no id → starts a new pool account add

Pool rows can Re-login through the same modal (gui/src/components/use-add-codex-account-oauth.ts). That is the correct tool for extra ChatGPT accounts, not for replacing native __main__.

The documented native path is ocx account main add / /api/native-main-profiles/*, which launches official codex login in a staging home and needs the OS keyring. On the published hub image that path is not usable: codex is not on PATH, and GET /api/native-main-profiles/doctor reports keyStore: unavailable, vaultStatus: missing, profileCount: 0.

#3417 tracks exposing native-main profiles in the WebUI (list/register/switch/recover). That issue explicitly says a browser cannot run official codex login itself, and new-profile enrollment is a follow-up. It does not cover deviceauth reauth of the existing __main__ grant on a container hub that has no Codex App and no codex binary.

#3366 closed the pool deviceauth gap. Native main was left on "use Codex App".

What should OpenCodex do?

Give the Codex Auth main card a device-login reauth that overwrites native __main__ / $CODEX_HOME/auth.json, visually separate from pool Add / pool Re-login.

Suggested contract:

  • Reuse the existing OpenAI deviceauth grant already used for pool add (loginChatGPTDevice / auth.openai.com/codex/device).
  • Persist tokens to the native main slot, not as a 13th pool account.
  • Refuse to treat __main__ as a pool id in /api/codex-auth/login (keep that 400), and instead add an explicit native-main device reauth route or a documented ocx account main reauth --device that the GUI can start/poll/cancel.
  • Do not require official codex on PATH or an OS keyring for this one operation on runtimeRole=hub.
  • Keep tokens, emails, and raw account ids out of GUI payloads/logs; show only URL + device code + status.

Until that exists, headless operators have no first-party way to recover a WHAM-revoked native grant without adding a pool account by mistake or copying auth.json from a workstation.

Example usage or interface

Codex Auth
  Main account (App login)
    [Re-login with device code]   ← missing today
    copy: open https://auth.openai.com/codex/device and enter ABCD-12345

  Account pool
    [Add]                         ← exists; must stay a new pool row
    row → [Re-login]              ← exists; must not target __main__
$ ocx account main reauth --device --no-wait
  url: https://auth.openai.com/codex/device
  deviceCode: ABCD-12345

Alternatives or workarounds

  • Codex Auth → Add / pool Re-login: works, but adds or refreshes a pool account. Completing that flow does not replace native __main__.
  • ocx account main add: requires official Codex CLI + keyring; not present on the hub image.
  • Copy workstation auth.json into the hub volume: works, but fights hub-owned credentials and is easy to get wrong.
  • feat(gui): expose native main login profiles in the WebUI #3417 profile switcher: only helps after an encrypted native profile already exists.

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 7, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 62 / 80

    이 이슈는 헤드리스 hub(Docker/k3s, Codex App 없음, oauthOpenBrowser: false)에서 Codex Auth의 native main(__main__, $CODEX_HOME/auth.json) 을 WebUI로 다시 로그인할 방법이 없다는 제품 구멍입니다. 풀 계정은 #3366/#3369/#3385 이후 deviceauth로 Add/Re-login이 됩니다. 그런데 main 카드는 App login 전용으로 잠겨 있고, 토큰이 만료·철회되면 codexAuth.mainTokenExpired(“Token expired — sign in again via Codex App login”) 문구만 보입니다. 운영자가 WHAM에서 token_revoked를 맞아도, 같은 프록시의 paused pool은 WHAM 200이 나올 수 있어 메인 슬롯 자격 증명만 죽은 상태가 됩니다. 페어링(ocx connect)은 클라이언트를 hub에 붙이는 일이고, native grant를 갈아끼우는 일이 아닙니다.

    현재 dev(2.47.0)에서도 그 구조는 그대로입니다. GUI main 카드는 reauth가 필요할 때 안내 문구만 띄우고, device-code 버튼을 달지 않습니다. API POST /api/codex-auth/login의 device 플로우는 풀 계정 생성·풀 reauth용으로만 열려 있습니다. __main__을 id로 넣으면 계정 id 검증에서 거절되고, main은 풀에 없으니 404, id 없는 reauth는 400, id 없는 device는 새 풀 계정 추가로 갑니다. 문서화된 native 경로(ocx account main add / /api/native-main-profiles/*)는 공식 codex login + OS keyring을 가정하는데, 공개 hub 이미지에는 codex가 PATH에 없고 doctor는 keyStore unavailable / vault missing을 보고합니다. #3417은 native-main 프로필 GUI(목록/전환/복구)이고, “브라우저가 공식 codex login을 대신 실행할 수 없다”고 못 박아 두었을 뿐, 컨테이너 hub의 기존 __main__ deviceauth 재인증은 범위 밖입니다.

    경로·심볼로 오늘 코드가 하는 일과 구멍은 이렇게 정리됩니다.

    • gui/src/components/codex-account-pool-main-card.tsx — showReauth일 때 t("codexAuth.mainTokenExpired")만 렌더. device Re-login 컨트롤 없음.
    • gui/src/components/use-add-codex-account-oauth.ts / AddCodexAccountModal — device: true로 /api/codex-auth/login을 치는 기존 UI. reauthAccountId는 풀 row용. main 카드와 연결되어 있지 않습니다.
    • src/codex/auth-api.ts (POST /api/codex-auth/login) — device === true면 startLoginFlow(..., { flow: "device" }). 하지만 isValidCodexAccountId가 __main__을 거부하고, reauth는 configuredPoolAccount만 허용합니다. 성공 시에도 풀 credential/풀 row를 갱신하는 경로입니다.
    • src/codex/account-id.ts — MAIN_CODEX_ACCOUNT_ID = "__main__", isValidCodexAccountId가 센티널을 명시적으로 제외. 풀 namespace에 main을 섞지 않으려는 설계이므로, __main__을 풀 id로 우회 허용하는 건 비추천입니다.
    • src/oauth/chatgpt-device.ts의 loginChatGPTDevice — OpenAI deviceauth(auth.openai.com deviceauth usercode/token) 구현이 이미 있습니다. 풀 Add가 쓰는 그 grant를 main 슬롯 persist에만 다시 꽂으면 됩니다.
    • src/cli/account-main.ts / src/codex/native-profile-api.ts — account main add|doctor|register|switch|recover와 /api/native-main-profiles/*. device reauth 서브커맨드·전용 라우트는 없습니다.
    • src/codex/main-account.ts — native auth.json 읽기/쓰기·토큰 갱신 경계. device 성공 토큰을 여기로 커밋하는 명시 API가 WebUI에 노출되어 있지 않습니다.

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

    • 새 라우트(예: /api/codex-auth/main/reauth-device) vs ocx account main reauth --device CLI를 GUI가 폴링하는 형태 vs 둘 다.
    • device 성공 후 identity 검증을 풀 reauth처럼 email/chatgptAccountId 일치로 강제할지, hub main은 “덮어쓰기”를 허용할지.
    • feat(gui): expose native main login profiles in the WebUI #3417 프로필 스위처와 일정을 묶을지, hub 운영 복구용으로 device main reauth만 먼저 얇게 넣을지.
    • main 카드 카피와 풀 Add/Re-login 카피를 시각적으로 어떻게 분리해 오조작(실수로 13번째 풀 row 생성)을 막을지.
    • runtimeRole=hub에서만 노출할지, desktop에서도 device main reauth를 허용할지.

    너의 추천

    풀 login API에 __main__을 억지로 넣지 마세요(지금 400은 맞습니다). 대신 native-main 전용 device reauth를 하나 만드세요: 기존 loginChatGPTDevice grant 재사용 → 토큰을 __main__/auth.json에만 persist → GUI main 카드에 “device code로 다시 로그인” 버튼 + URL/코드/상태만 표시. CLI는 ocx account main reauth --device [--no-wait]로 같은 백엔드를 타면 Docker 운영자가 WebUI 없이도 복구할 수 있습니다. keyring/codex 바이너리는 이 한 경로에서 요구하지 마세요. #3417은 프로필 전환 축으로 남기고, 이 이슈는 “죽은 main grant 복구”에 범위를 고정하면 mid-high(대략 60대)로 충분히 가치가 있습니다. 풀 Add를 임시 우회로 안내하면 자격 증명이 잘못된 버킷에 쌓이므로, 문서/카피에서도 “풀 Re-login ≠ main 복구”를 분명히 하세요.

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

  2. lidge-jun commented on Sep 13, 2026

    @lidge-jun
    Owner

    Landed via #4441 at 0c4f962

    L2 #4433 (native-main reauth API/CLI) + L3 #4441 (main-card Re-login with device code) are on dev. Headless hub operators can recover a WHAM-revoked native __main__ grant from the Codex Auth main card without the pool login path.

    Related stack still open: #4191 (L1 instrumentation landed via #4427; root cause may remain) and #4311 (L4 paginated writer still planned).

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

  3. lidge-jun commented on Sep 13, 2026

    @lidge-jun
    Owner

    Closing as completed: native-main device reauth UI+API shipped on dev via #4433+#4441 (merge 0c4f962).

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 requestlanded-via-maintainerOriginal PR closed after landing via a maintainer merge train

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions