Tenant Admin Console · Surface walkthrough

Tenant session required

A per-surface walkthrough of the Tenant Admin Console tenant-admin surface: layout, states, interactions, data, and cross-references.

drafted
8sections2 minread

On this page

Context. surface tenant-admin · domain meta · route /unauthorized · auth anon (public deny page) · source apps/oshun/tenant-admin/src/app/unauthorized/page.tsx

Last walked.

Purpose#

Public deny page shown when a request to a gated tenant-admin route has no valid session. It explains why access was refused and links back to the handoff so the identity provider can issue a session. One of two public paths (/unauthorized, /handoff) in src/middleware.ts.

Entry points#

  • Middleware redirect (src/middleware.ts) when a non-public path has no/invalid session token: /unauthorized?reason=<missing-session|invalid-session>&returnTo=<path>
  • Server-component redirect from every gated page when getTenantServerSession() returns null: /unauthorized?reason=missing-session&returnTo=<route>
  • Direct URL /unauthorized (public; no auth required)

Layout regions#

No shell chrome (TenantShell is not used — this is a bare page so no session leaks into the layout):

  • Main: <main data-testid="tenant-unauthorized-page">
    • <h1>Tenant session required</h1>
    • reason copy paragraph (from REASON_COPY[reason])
    • paragraph with the return to the handoff link

States#

  • Loading — N/A; static server component, no data fetch
  • Empty — N/A; always renders heading + copy + link
  • Populated (short)reason=missing-session (default) → "No tenant-admin session was found. Sign in through your identity provider and try again."
  • Populated (long) — N/A
  • Error (recoverable) — N/A; no query
  • Error (unrecoverable) — unknown reason value falls back to the missing-session copy; invalid-session → "Your tenant-admin session is no longer valid. Sign in again to refresh your scope claims."
  • Offline — static page; renders from cache if SW present (verify)
  • Gated — N/A; this IS the deny page (public path in middleware). No information leak — copy is generic and never echoes session data
  • Standalone PWA — verify; no manifest/SW confirmed in source

Interactions#

  • return to the handoff (link, next/link)
    • Function: navigates to /handoff?returnTo=<encoded returnTo> (encodeURIComponent); returnTo defaults to / when absent
    • Keyboard: only focusable element; Enter activates
    • Screen reader: announces "return to the handoff"
    • Touch target: standard inline link — verify ≥ 44×44 px hit area on coarse pointers
    • Mobile (≤ 640 px): no layout delta (no shell)
    • Offline behavior: navigation only; /handoff is a public path
    • Telemetry: None observed in source.

Data & contracts#

  • Reads: searchParams (reason, returnTo) from the URL only — no BFF/network read
  • Writes: None. (middleware separately deletes the oshun-tenant-session cookie when it redirected here with an invalid token)
  • Realtime: None.
  • Caching: static / SSR; depends only on query params
  • Auth/role check: none — /unauthorized is in middleware PUBLIC_PATHS

Cross-references#

Open questions / known gaps#

  • /handoff (the link target and other public path) has no walkthrough file in this scope; document it separately.
  • No telemetry/event is fired on this deny page; confirm whether a denied- access event is expected.