Files
ThothII/docs/superpowers/specs/2026-08-22-local-only-logout-visibility-design.md
T

5.3 KiB

Local-Only Logout Visibility Design

Date: 2026-08-22 Status: approved Scope: frontend visibility of the authenticated-shell logout control Source baseline: 912bab9

1. Purpose

ThothII has two distinct authentication journeys:

  • standalone Mac and Windows installations authenticate directly in ThothII with local accounts;
  • the Aritmolab server installation authenticates the user in the surrounding portal and exposes that trusted identity to ThothII.

The current authenticated shell always renders a Log out button. That action is meaningful for the standalone local-authentication journey, where ThothII owns the browser session. It is misleading in the server journey because leaving the authenticated environment is a portal-level operation, not a ThothII operation.

The frontend must therefore render the logout control only when the public authentication mode is exactly local.

2. Behavioral contract

The existing GET /auth/config response is the sole authority for logout visibility. The frontend applies this closed rule:

Public authentication mode Show Log out
local yes
upstream no
oidc no
none no
mock no

This deliberately hides the control for every current and future server-oriented non-local mode. It does not infer deployment type from the operating system, hostname, URL, user issuer, nullable session data, or build-time variables.

The authenticated user's display name remains visible in every mode. Only the Log out button is conditional.

3. Frontend design

AuthGate already loads and validates the public authentication configuration before it requests GET /me. It will derive a boolean logout capability from the retained configuration:

canLogout = config.mode === "local"

AuthGate passes this capability through AuthenticatedContent to AppShell. AppShell uses it only to decide whether to render the existing button. The current click handler, logout API coordinator, authentication-state cleanup, and query/session isolation behavior remain unchanged.

The capability is passed explicitly instead of being recomputed from AuthenticatedUser because legacy and upstream user representations may have nullable session data. It is also preferable to a new environment variable because /auth/config already represents the backend's effective authentication mode at runtime.

4. Backend and deployment impact

No backend route, authentication configuration, Compose descriptor, native tht command, or packaging logic changes.

POST /auth/logout remains available for the local standalone flow and for existing internal authentication behavior. Hiding a control is not treated as an authorization boundary; backend authentication and CSRF protections remain authoritative.

Mac and Windows packages require no platform detection. Their existing local authentication configuration produces mode: "local", so they retain the button automatically. The Aritmolab server's trusted-upstream configuration produces mode: "upstream", so it loses the button automatically.

5. Failure behavior

AuthGate continues to fail closed when /auth/config is unavailable or malformed; the authenticated shell is not rendered in that state. Once the configuration has been accepted, an unrecognized mode is already rejected by the existing parser and therefore cannot accidentally enable logout.

The visibility change introduces no new request, fallback, or error message. In non-local modes the button is absent and no user-initiated POST /auth/logout can originate from this shell control.

6. Verification

Frontend component tests will prove:

  1. AuthGate propagates logout capability for mode: "local" and disables it for mode: "upstream".
  2. AppShell renders Log out when logout capability is enabled and preserves the existing request-and-state-clear behavior.
  3. AppShell keeps the authenticated identity visible but does not render Log out when logout capability is disabled.
  4. The focused frontend tests, the complete frontend Vitest suite, TypeScript build-mode type-check, and production frontend build pass.

No live server mutation is required to validate this source change. A later manual server smoke test may confirm that the deployed Aritmolab journey shows the user identity without a ThothII logout control, while a standalone local-authentication smoke test confirms the control remains.

7. Non-goals

This change does not:

  • implement portal or global Aritmolab logout;
  • redirect users to an Aritmolab logout URL;
  • remove or weaken POST /auth/logout;
  • change login, expiry, session revocation, OIDC, or trusted-upstream behavior;
  • detect Mac, Windows, or server packaging in browser code;
  • alter any other authenticated-shell control or layout.

8. Acceptance criteria

The design is complete when:

  • Log out is present only for public authentication mode local;
  • the Aritmolab trusted-upstream server shell has no ThothII logout button;
  • standalone Mac and Windows local-authentication behavior is unchanged;
  • the username or display name remains visible in all authenticated modes;
  • no backend or deployment configuration is added solely for this visibility decision;
  • automated frontend tests prevent regression in both local and upstream modes.