Skip to content

[Feature]: persistent WebUI auth on remote binds — configurable session lifetime or non-token login #4055

Closed

Description

@nordz0r

Area

Dashboard

What are you trying to accomplish?

I operate the dashboard on a remote bind (non-loopback, behind a reverse proxy on a k3s/homelab hub). I open the dashboard from desktop and mobile browsers and need the session to persist across page reloads and browser restarts without re-entering the raw admin token.

What prevents this today?

Per the management-auth docs, session issuance is disabled whenever data-plane authentication is required (remote binds):

Session issuance is disabled whenever data-plane authentication is required, which includes remote binds. A remote operator must authenticate with the raw admin token; no loopback-style GUI session is minted.

Loopback binds get short-lived ocx_session_* credentials (5 minutes), but remote operators are left with the raw admin token prompt on every fresh page load / browser session. There is no configurable session lifetime and no alternative auth path for the remote-bind dashboard.

What should OpenCodex do?

When a remote operator enters the admin token once, the dashboard should issue a persistent GUI session (cookie with SameSite=Lax + HttpOnly) whose lifetime the operator controls, so that reloading the page or reopening the browser does not prompt for the token again until the configured TTL expires.

Concretely, at least one of:

  1. dashboard.sessionTtlMinutes config key (default 5 for loopback parity; remote operators can raise to hours/days at their own risk).
  2. Alternative non-token auth: reverse-proxy Basic auth pass-through, OIDC/SSO callback, or a "remember this device" scoped credential.

Example usage or interface

In ~/.opencodex/config.json:

{
  "dashboard": {
    "sessionTtlMinutes": 1440
  }
}

Or via CLI:

ocx config set dashboard.sessionTtlMinutes 1440

Before: reload dashboard → window.prompt("OpenCodex API token") on every page load.
After: reload dashboard → session restored from cookie until TTL expires; prompt only appears again after expiry.

Alternatives or workarounds

  • Storing the raw admin token in browser localStorage / password-manager autofill — defeats the masking posture the dashboard otherwise maintains (credential redaction in management responses).
  • Tunneling the dashboard through an SSH/loopback proxy so the loopback session path applies — awkward on mobile.

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. added
    enhancementNew feature or request
    guiDashboard, tray, settings UI
    proxyHTTP proxy, routing, reverse-proxy / management auth
    on Sep 8, 2026
  2. github-actions commented on Sep 8, 2026

    @github-actions
    Contributor

    Issue reopened

    The report now contains the information required by the automated check. Thanks for updating it.

  3. lidge-jun commented on Sep 8, 2026

    @lidge-jun
    Owner

    리뷰 · 우선순위 46 / 80

    이 이슈는 non-loopback(원격 바인드) 대시보드를 k3s/홈랩 리버스 프록시 뒤에서 쓸 때, 페이지를 다시 열거나 브라우저를 재시작할 때마다 raw admin token을 다시 치고 싶지 않다는 요청입니다. 작성자가 인용한 management-api 문구(“data-plane auth가 필요하면 session issuance 비활성 · 원격 운영자는 raw admin token만”)는 문서에 아직 그대로 있고, 체감도 “매 로드마다 토큰 폼”에 가깝습니다. 제안은 dashboard.sessionTtlMinutes로 TTL을 늘리거나, 쿠키(SameSite=Lax+HttpOnly)로 GUI 세션을 유지하거나, Basic/OIDC/“이 기기 기억” 같은 non-token 로그인입니다.

    지금 dev HEAD(164bd2b36, package 2.49.0)의 실제 코드는 문서 한 줄보다 앞서 있습니다. loopback은 API auth가 없을 때만 issueGuiSession이 ocx_session_*를 만들고 TTL은 LOOPBACK_GUI_SESSION_TTL_MS = 5분입니다(src/server/gui-session.ts). 원격에서는 이미 두 갈래가 있습니다. (1) runtimeRole === "hub" + trusted Tailscale ingress + remoteGui.allowedTailscaleUsers 일치 + HTTPS origin 허용이면 tailscale-identity 세션을 발급하고 TTL은 REMOTE_GUI_SESSION_TTL_MS = 12시간. (2) hub pairing grant(ocx_pair_*)를 한 번 쓰고 세션을 받는 경로. remote-hub 가이드도 “admin token은 일반 관리는 되지만 브라우저 session을 mint하거나 consent 행위(별 찍기 등)를 승인하지 못한다”고 못 박습니다. management-api 본문에도 “An admin token … can never mint or exchange into a consent session”이 있습니다.

    그래서 이슈가 원하는 “admin token 한 번 입력 → 서버가 긴 TTL 쿠키 세션 발급” 은, 지금 제품의 의도적 보안 경계와 정면으로 부딪칩니다. GUI는 gui/src/api.ts에서 세션을 메모리만 유지하고, remote에서 세션을 못 받으면 promptForAdminToken(gui/src/admin-token-dialog.ts) 비밀번호 폼을 띄웁니다. 토큰은 localStorage/sessionStorage에 안 씁니다(웹 대시보드 문서·#647 이후 자세). 브라우저 비밀번호 관리자 autofill은 이미 허용된 완화책입니다. 쿠키 HttpOnly 세션으로 바꾸려면 bootstrap meta 주입·CSRF·origin 바인딩·logout 계약을 통째로 다시 짜야 합니다.

    설정 키 dashboard.sessionTtlMinutes는 HEAD src/config.ts / types에 없습니다. 넣으면 types/config 분할 캠페인과 겹칠 수 있어, naive config PR은 close-don't-rebase 후보입니다. 이미 있는 원격 TTL(12h)을 이미 발급된 remote/pairing/Tailscale 세션에만 노출·조정하는 얇은 설계는 가능하지만, “admin → session 교환”과는 별개입니다. 관련 #3898(헤드리스 hub에서 native main reauth 구멍), #3859(이메일 마스킹·원격 신뢰 모델)는 같은 배포 모양의 이웃이지 중복이 아닙니다. #647(닫힘)은 요청마다 프롬프트 폭주를 고친 것이고, 이 이슈는 그 다음 단계(로드/재시작 간 지속)를 말합니다.

    경로 docs-site/.../management-api.md “Session issuance is disabled…” - 문서가 loopback-only 서술에 머물러 있음. Tailscale/pairing 경로와 어긋남
    경로 src/server/gui-session.ts LOOPBACK_GUI_SESSION_TTL_MS / REMOTE_GUI_SESSION_TTL_MS / issueGuiSession - 원격 세션은 hub+Tailscale(또는 pairing)만. admin token 교환 없음. 원격 TTL 이미 12h
    경로 src/server/management-auth.ts resolveManagementAdmission - admin-token과 gui-session principal 분리. consent는 세션만
    경로 docs-site/.../guides/remote-hub.md Trust boundaries - admin token으로 session mint 금지가 명시 설계
    경로 gui/src/api.ts storeSession / 메모리 only - 쿠키·persistent storage 없음. reload 시 bootstrap/rebootstrap 또는 admin 폼
    경로 gui/src/admin-token-dialog.ts - 비밀번호 폼 + 브라우저 autofill 유도. OCX 자체는 토큰 비지속
    설정 dashboard.sessionTtlMinutes - 스키마 없음. 추가 시 config/types 분할과 충돌 위험

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

    • k3s/일반 리버스 프록시(non-hub) 운영자를 hub+Tailscale/pairing으로 유도할지, standalone remote에 별도 완화책을 열지
    • admin token → gui-session 교환을 절대 금지로 유지할지(권장), 예외 opt-in을 둘지
    • 이미 있는 remote 세션 TTL(12h)만 config로 노출할지, loopback 5분과 키를 합칠지
    • HttpOnly 쿠키 세션으로 옮길지(큰 인증 개편) vs 문서·pairing DX만 고칠지
    • OIDC/Basic pass-through는 roadmap([Roadmap] Centrally hosted multi-user OpenCodex with tenant isolation #95 multi-user) 축으로 미룰지

    너의 추천
    enhancement로 유지하되 design-first. admin-token→session mint PR은 거절. 먼저 management-api/web-dashboard 문장을 HEAD 코드에 맞게 고치세요(원격은 Tailscale allowlist 또는 ocx connect pairing으로 12h gui-session, admin token은 관리 API용·consent 아님). k3s 사용자는 hub management ingress + pairing/Tailscale을 정식 경로로 안내하고, SSH/loopback 터널은 문서화된 워크어라운드로 남기세요. TTL만 늘리고 싶다면 이미 발급된 remote 세션의 REMOTE_GUI_SESSION_TTL_MS를 좁은 config로 노출하는 후속만 검토하세요. dashboard.sessionTtlMinutes 큰 스키마·쿠키 영속·OIDC는 2.49.x 마감 밖·types/config 분할과 겹치면 닫고 다시. #3898/#3859와 중복 close는 하지 마세요.

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

  4. lidge-jun commented on Sep 10, 2026

    @lidge-jun
    Owner

    Additional deployment evidence for the repeated admin-token prompt on refresh:

    • Hub: macOS, source checkout dev at 6d3ad12e3 (2.51.0).
    • Browser: Chromium-based embedded browser on Windows 11, accessing the hub through Tailscale Serve HTTPS and the dedicated management ingress.
    • The operator reported that entering a valid management admin token works, but refreshing asks for it again. Independently confirmed the admin-token dialog on a fresh page load before the configuration change.
    • gui/src/api.ts keeps the accepted credential in in-memory runtime session state and explicitly removes the legacy sessionStorage token. Thus reload persistence should not be represented as an existing token-save option.

    Supported workaround verified without a source patch:

    {
      "remoteGui": {
        "allowedTailscaleUsers": ["operator@example.com"]
      }
    }

    After configuring the operator's exact Tailscale login, restarting the hub, and accessing the trusted Tailscale management ingress, the dashboard opened without entering an admin token. Two successive full-page reloads retained working dashboard access by issuing fresh Tailscale-identity sessions. No admin token was persisted in browser storage.

    UX suggestion: when the remote admin-token dialog is shown, explain whether the entered credential lasts only until reload and surface the supported Tailscale identity setup (or a bounded persistent-session option if implemented). The current help text explains the token's file location and environment override, but does not help the operator understand why they must paste it repeatedly.

    This comment intentionally omits real account names, tailnet addresses, tokens, and session metadata.

  5. added
    priority: P3Low: new provider/client integration, large or experimental feature (>2000 LOC or >50 files), RFC/ro
    on Sep 24, 2026
  6. lidge-jun commented on Sep 27, 2026

    @lidge-jun
    Owner

    Closing, because the case reported on 2.51.0 (Tailscale Serve) is covered on dev. With remoteGui.allowedTailscaleUsers on the Tailscale management ingress, the dashboard gets a 12-hour identity session that each authorized request extends (#2776). A reload bootstraps a fresh session without the token prompt. The management API reference said remote binds never get a session, which was wrong; #6066 (merge 7d8459388c) corrects it. A generic reverse proxy without a Tailscale identity still uses the admin token or a pairing grant. That is the intended boundary, since an admin token does not mint browser sessions.

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

    enhancementNew feature or requestguiDashboard, tray, settings UIpriority: P3Low: new provider/client integration, large or experimental feature (>2000 LOC or >50 files), RFC/roproxyHTTP proxy, routing, reverse-proxy / management auth

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions