Skip to content

feat(server): persistent origin-scoped dashboard sessions via POST /api/auth/session - #3080

Draft
x3M3x wants to merge 4 commits into
lidge-jun:devfrom
x3M3x:codex/dashboard-session-persistence
Draft

feat(server): persistent origin-scoped dashboard sessions via POST /api/auth/session#3080
x3M3x wants to merge 4 commits into
lidge-jun:devfrom
x3M3x:codex/dashboard-session-persistence

Conversation

@x3M3x

@x3M3x x3M3x commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds POST /api/auth/session: the dashboard exchanges the admin token once for a 12-hour opaque, process-local session. The browser stores only that opaque session (never the raw admin token) in origin-scoped local storage and re-arms requests after refresh without re-prompting.
  • Sessions are bound to the exact validated dashboard origin: the browser Origin header when the mint request carries one (this covers TLS-terminating reverse proxies with an allowlisted external https:// origin), the request origin otherwise. Mutations additionally require the per-session CSRF token; a session minted for one origin never admits another.
  • Transport policy for the first exchange is explicit: loopback origins mint by default, an explicitly allowlisted non-loopback HTTPS origin mints because the corsAllowOrigins entry is itself the opt-in, and a non-loopback plain-HTTP origin requires the new server.allowRemoteDashboardSessions config flag (default false). No 12-hour localStorage credentials appear on existing hostname deployments without an operator decision.
  • The claimed dashboard origin header is mandatory on every method, safe ones included; only the CSRF token and the browser Origin stay mutation-only.
  • Works on the regular listener (loopback and hostname binds alike). Unlike feat(server): authenticated remote dashboard listener with origin-scoped sessions #2414, no dedicated remote listener is required: the existing hostname bind already controls where the dashboard is reachable. Every session endpoint response carries Cache-Control: no-store.

Supersedes the session-persistence half of #2414; the dedicated-listener part of that PR is no longer needed now that the proxy supports hostname binds. #2414 is closed in favor of this PR.

Verification

  • bun run typecheck
  • bun run privacy:scan
  • bun test tests/dashboard-session-endpoint.test.ts (11 pass): mint/admission/CSRF/cross-origin coverage plus review regressions: GET without or with mismatched claimed origin returns 401; non-loopback plain-HTTP mint refused by default and allowed with the opt-in flag; external-HTTPS-origin over internal-HTTP-Host proxy topology (mint binding plus safe-request admission); no-store asserted on every response.
  • bun test ./tests/api-auth-persistent-session.test.ts inside the dashboard client workspace (5 pass): persisted-session restore, cross-origin discard, mint-on-sign-in, failed-mint fallback, rejected-session cleanup (happy-dom).
  • The injected dashboard-session bootstrap test (loopback session issuance with CSRF) passes; remaining tests/server-management-auth.test.ts failures on this host are the ENOENT config temp-file races documented below and reproduce identically on a pristine origin/dev checkout.
  • bun run test:changed was attempted: 4890 pass / 248 fail, all failures being ENOENT races in config temp-file writes and 5s timeouts under parallel load. The same failure class reproduces on a pristine origin/dev worktree (bun test tests/server-management-auth.test.ts: 14 fail there too), confirming an environment/host issue, not this diff. A full bun run test run hit the repository 900s parallel-suite watchdog on the same busy host.
  • Docs updated: structure/05 (credential table row plus persistent-session paragraph), docs-site server configuration reference (allowRemoteDashboardSessions row), docs-site management API reference (Persistent dashboard sessions section covering storage, expiry, restart invalidation, secure transport, and opt-in).
  • Security-sensitive area: this touches management auth. Independent maintainer auth/security review is requested.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed. (structure/05, configuration/server.md, reference/management-api.md)
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults. (Admin token is never persisted client-side; only the opaque session is; remote plain-HTTP sessions default off; privacy scan green.)

Review readiness checklist

This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:

  • All CI tests are green on my local testing.

  • I pushed my PR to the latest dev commit.

  • I resolved all correct Codex and CodeRabbit findings.

  • My PR is ready for review.

@coderabbitai

coderabbitai Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the intake: hygiene-blocked Deterministic PR hygiene checks failed label Aug 31, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Deterministic hygiene checks failed.

  • unsponsored_surface — This changes an authentication, workflow, release-automation, or dependency surface. MAINTAINERS.md requires security review for these; ask a maintainer to apply maintainer-sponsored once they have reviewed it. Paths: src/server/auth-cors.ts, src/server/management-auth.ts.

@github-actions

github-actions Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

⏳ DRAFT

  • UI screenshot required. hygiene: unsponsored_surface.

What to do

  • Add a screenshot of the UI change to the PR description.
  • Fix unsponsored_surface — This changes an authentication, workflow, release-automation, or dependency surface. MAINTAINERS.md requires security review for these; ask a maintainer to apply maintainer-sponsored once they have reviewed it. Paths: src/server/auth-cors.ts, src/server/management-auth.ts.
  • Tick all four boxes in the PR description once you're done (currently 0/4).

Review readiness checklist

  • ⬜ All CI tests are green on my local testing.
  • ⬜ I pushed my PR to the latest dev commit.
  • ⬜ I resolved all correct Codex and CodeRabbit findings.
  • ⬜ My PR is ready for review.

0/4 boxes ticked.

This pull request was already a draft. Its draft status will be preserved after every issue above is resolved.
@x3M3x Tick the boxes once your local CI is green, your branch is on the latest dev commit, and every correct Codex and CodeRabbit finding is resolved.

@Ingwannu Ingwannu left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes on exact head 4a76dc9f434a1f7c4acea520b3a06482cedb174d. The opaque process-local session direction is useful, but this draft weakens an existing admission boundary and does not yet have a safe remote transport/origin contract.

  1. src/server/management-auth.ts:300-302 changes the existing session rule from claimedOrigin === session.origin to !claimedOrigin || claimedOrigin === session.origin. A stolen session token can therefore authorize every GET/HEAD management read with only a matching request URL/Host and no GUI-origin arm. The GUI already sends X-OpenCodex-GUI-Origin for session requests. Keep that header mandatory for safe methods too; only the CSRF token and browser Origin may be mutation-only. Add a negative GET test with the session token but no/mismatched claimed origin.

  2. POST /api/auth/session is mounted on the ordinary listener for every configuration, even a non-loopback plain-HTTP hostname bind. The comment that “the credential, not the transport, carries the trust” is not valid for the first exchange: the raw long-lived admin token crosses that transport. Require an explicit persistence/remote-session opt-in and refuse non-loopback insecure origins by default, or retain a dedicated authenticated TLS/trusted-proxy boundary. Do not silently enable 12-hour localStorage credentials on every existing hostname deployment.

  3. TLS termination is currently broken even when the operator explicitly allowlists the external origin. isAllowedManagementOrigin accepts an external https://... Origin through corsAllowOrigins, but issueGuiSessionForAdmin stores managementRequestOrigin(req, config), derived from the server-observed request URL/Host (commonly http://... behind a reverse proxy). The GUI then rejects the returned session because it does not equal window.location.origin. Bind to the exact validated browser Origin when present, with an explicit trusted-proxy policy, or reject this topology. Add an external HTTPS-Origin/internal-HTTP regression.

  4. handleGuiSessionEndpoint says the route is mounted only on a dedicated remote listener, while src/server/index.ts:1058-1064 mounts it on the regular listener and the PR body explicitly removes the dedicated listener. Correct the contract and update structure/05_gui-and-management-api.md plus user docs for storage, expiry, logout/restart invalidation, secure transport, and opt-in behavior. Return the token response with explicit Cache-Control: no-store.

  5. The readiness claim is not supported yet: repository hygiene/target checks are red and the author reports 248 changed-suite failures plus a full-suite watchdog expiry. Keep this Draft, rebase after the 2.39.0 dev version bump, and obtain exact-head auth/server plus GUI tests, typecheck, privacy, builds/lint, and hosted matrix results before requesting security sponsorship.

@lidge-jun

Copy link
Copy Markdown
Owner

리뷰 · 우선순위 54 / 80

이 PR은 대시보드 로그인 한 번이 새로고침마다 다시 안 뜨게 하려는 칸입니다. 관리자 토큰을 브라우저에 안 남기고, 서버가 만든 불투명 세션만 12시간 동안 같은 출처(origin)에 붙입니다. 파일은 여섯입니다. gui/src/api.ts, gui/tests/api-auth-persistent-session.test.ts, src/server/auth-cors.ts, src/server/index.ts, src/server/management-auth.ts, tests/dashboard-session-endpoint.test.ts입니다. 더하기 527, 빼기 40입니다. 베이스는 dev입니다. 초안입니다. 작성자는 x3M3x입니다. 라벨은 enhancement와 intake: hygiene-blocked입니다. 하이진은 unsponsored_surface와 UI 스크린샷 없음으로 막혀 있습니다. 지금 dev HEAD는 5cec0a33e입니다. 자격(entitlement) 스택과 Aside 마크 쪽이 막 들어온 뒤입니다. 이 PR은 그 열차와 겹치지 않습니다. 원격 hostname 바인드 대시보드 UX용입니다. 점수 54.

지금 HEAD에서 루프백 대시보드는 이미 짧은 GUI 세션이 있습니다. src/server/management-auth.tsissueGuiSession은 GET이고, 루프백 Host일 때만, TTL은 GUI_SESSION_TTL_MS(5분)입니다. HTML 메타로 심고 gui/src/api.tsloadInjectedSession / reBootstrapSessionToken/opencodex-session으로 다시 받습니다. 관리자 토큰은 메모리에만 둡니다. 주석도 "never write tokens to web storage"입니다. 원격(hostname)에서는 그 주입이 없어서, 새로고침마다 관리자 토큰을 다시 묻습니다. 이 PR이 그 구멍을 막습니다.

서버 쪽은 POST /api/auth/session입니다. handleGuiSessionEndpoint가 관리 게이트보다 먼저 붙습니다. issueGuiSessionForAdmin이 관리자 토큰과 isAllowedManagementOrigin을 확인한 뒤 mintGuiSession(..., GUI_PERSISTENT_SESSION_TTL_MS)로 12시간 세션을 만듭니다. 루프백 전용 주입 경로(issueGuiSession)는 그대로 둡니다. 공통 발급은 mintGuiSession으로 모았습니다. 수락 검사는 guiSessionAdmitted로 모았습니다. CORS 쪽은 ManagementPolicyView = Pick<OcxConfig, "hostname" | "corsAllowOrigins">로 좁혔습니다. #1102의 리스너별 policy view 패턴과 맞습니다.

클라이언트는 opencodex-gui-session 키로 localStorage에 token/csrf/origin/expiresAt만 넣습니다. 관리자 토큰 문자열은 넣지 않습니다. 테스트가 그걸 확인합니다. 로그인 성공 뒤 mintPersistentGuiSession이 실패해도 이번 탭의 메모리 관리자 토큰은 남깁니다. 401이 나면 persisted 세션을 지우고 다시 묻습니다. #2414(전용 remote listener + 세션)는 이미 CLOSED입니다. 본문이 말한 대로 hostname bind가 있으니 전용 리스너는 이 칸에 없습니다. types.ts/config.ts 분할과 무관합니다. 프리뷰 배포는 계획에 없습니다.

다만 문서와 게이트에 남은 티끌이 있습니다. handleGuiSessionEndpoint JSDoc은 아직도 "dedicated remote dashboard listener에만 마운트"라고 적습니다. 실제 src/server/index.ts는 일반 /api/ 경로에 붙입니다. 본문과도 어긋납니다. index.ts의 method!==POST 405 분기는 handleGuiSessionEndpoint가 이미 405 Response를 돌려주므로 도달하지 않습니다. GET 수락은 예전보다 느슨합니다. 예전 requireManagementAuth는 세션일 때 claimedOrigin === session.origin이 필수였습니다. 새 guiSessionAdmitted는 안전한 메서드에서 claimedOrigin이 비어 있어도 Host에서 만든 requestOrigin만 맞으면 통과합니다. GUI fetch는 origin 헤더를 붙이지만, 세션 토큰만 들고 오는 외부 클라이언트의 GET은 예전보다 쉽습니다. localStorage에 12시간 불투명 세션을 두는 선택은 XSS가 그 세션을 훔칠 수 있다는 뜻입니다. 관리자 토큰을 안 넣는 건 맞지만, 위험 창은 5분 주입보다 깁니다. 프로세스 로컬이라 프록시 재시작 뒤 클라 저장값은 401 전까지 남아 있습니다. 테스트가 그 청소를 봅니다. 게이트는 UI 스크린샷과 maintainer-sponsored가 필요합니다. 인증 표면이라 MAINTAINERS.md 보안 리뷰 칸입니다.

경로 handleGuiSessionEndpoint JSDoc - 전용 remote listener에만 붙는다고 적혀 있다. 실제는 일반 listener의 /api/auth/session이다
경로 src/server/index.ts GUI_SESSION_ENDPOINT_PATH 405 분기 - handleGuiSessionEndpoint가 이미 405를 반환한다. 죽은 코드다
경로 guiSessionAdmitted safeMethod - claimedOrigin이 없어도 GET/HEAD가 통과한다. 예전 세션 수락보다 느슨하다
경로 gui/src/api.ts PERSISTENT_GUI_SESSION_KEY - localStorage에 12시간 불투명 세션을 둔다. XSS 창이 5분 주입보다 길다
경로 issueGuiSessionForAdmin / mintGuiSession - 관리자 토큰 교환과 origin 바인딩 자체는 HEAD의 세션 모델과 맞다
경로 #2414 - 이미 CLOSED다. 이 PR이 세션 절반을 이어 받는 설명과 맞다
경로 intake: hygiene-blocked - unsponsored_surface + UI 스크린샷 없음. enforce-target도 같은 이유로 fail이다

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

  • localStorage 12시간 불투명 세션을 원격 대시보드 UX로 받아들일지, 더 짧은 TTL·HttpOnly가 아닌 헤더 유지 이유로 그대로 둘지
  • GET에서 claimedOrigin 완화를 의도된 계약으로 잠글지, 예전처럼 필수 헤더로 되돌릴지
  • 인증 표면이라 maintainer-sponsored를 누가 붙일지. 스크린샷 요구를 인증 API에 어떻게 적용할지(면제 vs 로그인 화면 한 장)

너의 추천
초안 유지한 채 JSDoc과 죽은 405 분기만 고치고, 메인테이너 보안 리뷰 후 maintainer-sponsored를 붙이세요. claimedOrigin GET 완화는 리뷰에서 한 줄로 계약에 적거나 예전 규칙으로 되돌리세요. 스크린샷은 로그인 유지 전후 한 장이면 게이트용으로 충분합니다. #2414는 이미 닫혀 있으니 다시 닫을 일 없습니다. 분할 무효화·중복 닫기 해당 없음. 지금 entitlement/Aside 열차와 겹치지 않으니 급히 끼워 넣을 칸은 아닙니다. 라벨은 바꾸지 않습니다.

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

@x3M3x

x3M3x commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

Thank you for the detailed review. All five points are addressed in 56ba6f4:

  1. Claimed origin on safe methods (restored). The admission check again requires the claimed dashboard origin header to equal the session origin on every method, GET and HEAD included. Only the CSRF token and the browser Origin header stay mutation-only. Added the requested negative regression: GET with a valid session token but no or mismatched claimed origin returns 401.

  2. Transport opt-in. Added server.allowRemoteDashboardSessions (default false). POST /api/auth/session now refuses a non-loopback plain-HTTP dashboard origin unless the operator sets it. Loopback origins mint by default, and an explicitly allowlisted non-loopback HTTPS origin mints because the corsAllowOrigins entry is itself the explicit opt-in. Regressions cover refuse-by-default and allowed-with-flag for the same remote origin.

  3. TLS-terminating proxy topology. Minting now binds the session to the exact validated browser Origin header when present (the request has already passed the management-origin admission, so the external https:// origin is allowlist-validated), falling back to the request origin for header-less same-origin POSTs. For safe requests from the external page the browser sends no Origin header while the process observes the internal http:// Host, so admission re-asserts the binding through the now-mandatory claimed header; when a browser Origin header is present it must still match the session origin, and mutations keep the full CSRF arm. Added the external-HTTPS-origin / internal-HTTP-Host regression covering mint binding and both safe-request admission paths.

  4. Contract and docs. The stale dedicated-listener docstring is corrected: the route is mounted on the ordinary management listener, and the description now says so. Every endpoint response carries Cache-Control: no-store. Updated the credential-boundary SOT (structure/05: extended the session table row and added a persistent-session paragraph covering storage, expiry, logout/restart invalidation, secure transport, and opt-in) and the user docs: a new allowRemoteDashboardSessions row in the server configuration reference and a Persistent dashboard sessions section in the management API reference.

  5. Process. Staying in draft with the readiness checklist unticked. Dev has not yet moved to the 2.39.0 bump as of this push, so the rebase is pending. On this host, typecheck, the privacy scan, the 11 dashboard-session endpoint tests, the 5 dashboard client persistence tests, and the injected-session bootstrap test all pass; the remaining server-management-auth failures are the documented ENOENT temp-file races that reproduce identically on a pristine dev checkout here.

One note: the PR description was reworded to drop a literal string that falsely tripped the screenshot requirement, since this PR changes no rendered interface pixels.

@Ingwannu Ingwannu left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed exact head 56ba6f411e38d6eb7b51144bb16ccefcc365141e. The mandatory claimed-origin arm, TLS-terminator binding, no-store responses, stale contract text, and focused negative tests address the concrete blockers from my prior review. Two policy/lifecycle boundaries remain before sponsorship.

  1. persistentSessionTransportAllowed enables every non-loopback HTTPS origin without allowRemoteDashboardSessions, treating an existing corsAllowOrigins entry as consent to a new 12-hour bearer in localStorage. That allowlist previously meant only “this origin may call the management API”; upgrading must not silently widen it into persistent credential storage. Make allowRemoteDashboardSessions === true the explicit gate for every non-loopback persistent mint. Then separately require HTTPS, or a clearly documented private/tailnet plain-HTTP exception, inside that opted-in path. Loopback can retain its existing short-lived injected-session behavior without the persistent feature.

  2. The docs say “dashboard logout deletes it,” but the implementation only removes localStorage. The server-side bearer remains valid in state.sessions until expiry or process restart, so a copied token survives logout for up to 12 hours. Either add an authenticated, CSRF-protected session-revocation/logout operation that deletes the exact server record and have the GUI call it best-effort before local cleanup, or state explicitly that logout is client-local and does not revoke a stolen session. For a full-management bearer, server revocation is the preferable contract; add a regression that the revoked token no longer authorizes reads or mutations.

The browser-origin/claimed-header checks protect browser-origin use; they should not be documented as making a copied bearer non-replayable by a non-browser client. Keep the localStorage/XSS tradeoff explicit.

This branch is now six commits behind current dev@06d688087 (2.39.0), and exact-head hygiene/target are still red with no hosted runtime/GUI matrix. Keep it Draft, rebase after these changes, then run the required isolated auth/server tests, full GUI test/lint/build, docs build, typecheck, privacy scan, and hosted CI before requesting maintainer-sponsored.

x3M3x added 2 commits August 31, 2026 19:41
…pi/auth/session

Exchanges the admin token once for a 12-hour opaque, process-local session bound to the exact dashboard origin with a per-session CSRF token. The GUI persists only the opaque session (never the admin token) in origin-scoped localStorage and re-arms requests after refresh without re-prompting. Serves on the regular listener; no dedicated remote listener required.
- Require X-OpenCodex-GUI-Origin on safe methods again; only CSRF and the browser Origin stay mutation-only.
- Gate POST /api/auth/session transport: loopback mints by default, allowlisted HTTPS is its own opt-in, non-loopback plain HTTP requires server.allowRemoteDashboardSessions.
- Bind sessions to the validated browser Origin so TLS-terminating proxies bind to the external allowlisted origin; safe requests re-assert the binding via the claimed header when no Origin header is present.
- Send Cache-Control: no-store on every /api/auth/session response; correct the mounted-on-ordinary-listener contract.
- Document storage, expiry, invalidation, secure transport, and opt-in in structure and docs-site; add regression tests for each.
@x3M3x
x3M3x force-pushed the codex/dashboard-session-persistence branch from 56ba6f4 to 8b41020 Compare August 31, 2026 15:41
@x3M3x

x3M3x commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto current origin/dev (06d688087) and pushed 8b4102023 to the PR branch.

Verified on the rebased head:

  • bun run typecheck
  • bun test tests/dashboard-session-endpoint.test.ts (11 pass)
  • bun run privacy:scan

The review findings remain addressed: mandatory claimed origin on safe methods, explicit insecure-remote opt-in, TLS-terminating proxy origin binding, corrected route/docs contract, and Cache-Control: no-store. The PR remains draft pending maintainer security sponsorship and hosted CI.

@x3M3x

x3M3x commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the latest review boundaries in 0635b95 and pushed to the fork branch.

  • Every non-loopback persistent dashboard session now requires �llowRemoteDashboardSessions: true, including allowlisted HTTPS origins.
  • Added CSRF/origin-bound POST /api/auth/session/revoke; the GUI calls it best-effort before clearing a persistent session, and server-side revocation blocks subsequent reads/mutations.
  • Verification: �un test tests/dashboard-session-endpoint.test.ts (13 pass), �un run typecheck (pass), �un run privacy:scan (pass).

The PR remains draft pending hosted CI and maintainer security sponsorship.

@x3M3x

x3M3x commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

The latest hosted run confirms the code-side review work is complete on 0635b9549.

  • hygiene is blocked only by unsponsored_surface for src/server/auth-cors.ts and src/server/management-auth.ts.
  • enforce-target is consequently blocked by the same sponsorship requirement.
  • resolve-pr, label checks, and CodeRabbit are green.

No further code change is warranted from this result. Please have a maintainer/security reviewer apply maintainer-sponsored after review; the PR remains draft as required.

@Ingwannu Ingwannu left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed exact head 0635b9549a0b26805085c7f6f9788ceda8fea99a. The two prior policy/lifecycle blockers are fixed in code: every non-loopback persistent mint now requires allowRemoteDashboardSessions === true, and a CSRF/origin-admitted revoke removes the server-side session so it cannot be reused.

I am keeping changes requested because the security contract and its coverage are now inconsistent with that implementation:

  1. Update every stale contract statement. issueGuiSessionForAdmin() still says an allowlisted HTTPS origin is its own opt-in. structure/05_gui-and-management-api.md, docs-site/.../management-api.md, and docs-site/.../configuration/server.md still say loopback and allowlisted HTTPS mint without the flag, and describe the flag as plain-HTTP-only. The code now correctly requires the flag for every non-loopback origin. Document that gate first, then the additional HTTPS/CORS allowlist or explicitly risky plain-HTTP condition. This is an auth boundary, not cosmetic wording.

  2. The docs say “dashboard logout” deletes/revokes the session, but this branch does not expose or wire an explicit logout action. clearToken() is reached only from 401 retry handling. Either wire the actual user logout path to clear and revoke, or describe the implemented lifecycle honestly as rejection/expiry cleanup rather than claiming a UI action that does not exist.

  3. Add GUI-level coverage proving the clear/logout path sends exactly one revoke request with the session token, claimed origin, and CSRF evidence, removes localStorage immediately, and never reuses that token afterward. The new server test proves the endpoint itself, but not the browser lifecycle claimed by the PR.

This head has diverged from current dev, remains Draft/hygiene-blocked, and has no exact-head cross-platform GUI/auth CI. Rebase after these changes; sponsorship and approval remain gated on that final exact head.

@x3M3x

x3M3x commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Pushed 3e8b06e with the remaining review fixes.\n\n- Corrected the auth contract in the JSDoc, structure SOT, management API docs, and server configuration docs: every non-loopback persistent session requires allowRemoteDashboardSessions: true, followed by the HTTPS/allowlist or explicitly risky private/plain-HTTP policy.\n- Clarified the actual GUI lifecycle: rejection-driven session clearing removes localStorage immediately and attempts best-effort server revocation; there is no separate dashboard logout action in this path.\n- Added GUI regression coverage proving exactly one revoke request carries the session token, claimed origin, and CSRF token, localStorage is removed immediately, and the rejected token is not reused.\n\nVerified: GUI persistent-session tests (6 pass), dashboard session endpoint tests (13 pass), typecheck, privacy scan, GUI build, and docs build. GUI lint could not load the repository's TypeScript oxlint plugin under the installed oxlint runtime; no source lint changes were made. Maintainer security sponsorship (maintainer-sponsored) and hosted exact-head CI remain required; the PR stays draft.

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

Labels

enhancement New feature or request intake: hygiene-blocked Deterministic PR hygiene checks failed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants