Source: apps/oshun/admin/src/lib/session-cookie.ts,
apps/oshun/admin/src/lib/server-session.ts,
apps/oshun/admin/src/lib/customer-session.ts,
apps/oshun/admin/src/app/handoff/page.tsx,
apps/oshun/admin/src/app/handoff/HandoffLauncher.tsx,
apps/oshun/admin/src/app/unauthorized/page.tsx,
libs/oshun/navigation/src/admin-ia.ts
(OSHUN_ADMIN_WORKSPACE_MODEL.requiredScopes, canEnterAdminWorkspace)
How an operator becomes an operator — the privileged handoff, the session cookie, the scopes, and the unauthorized fallback.
Three cookies you need to know#
| Cookie | Owner | Purpose |
|---|---|---|
OSHUN_ADMIN_SESSION_COOKIE_NAME (admin) |
Admin | Gates every non-public admin path via middleware |
OSHUN_CONSUMER_SESSION_COOKIE_NAME (consumer) |
V1 PWA | Customer session; admin's /handoff reads it to know whether to offer a privileged-handoff prompt |
The admin and consumer cookies are scoped separately. A customer session alone does NOT confer admin access — explicit privileged handoff is required.
Auth states#
- anonymous — no cookies; gated paths bounce to
/unauthorized - customer-only — only the consumer cookie; visiting an admin path
bounces to
/unauthorized?reason=missing-session; visiting/handoffoffers the privileged-handoff flow - admin (valid) — admin cookie parses cleanly; can access any path their
scopesallow - admin (invalid) — admin cookie present but
parseAdminSessionTokenreturns null; middleware deletes the cookie and bounces to/unauthorized?reason=invalid-session - admin + insufficient scope for workspace — middleware lets the request
through (it only checks for any valid admin session), but the page's
WorkspaceEntryPointrenders an "Access not granted" panel and the BFF returnsaccessible: false
Sign-in flow: privileged handoff#
apps/oshun/admin/src/app/handoff/page.tsx
- Visit
/handoff— public path (no admin session required) - Has admin session already —
parseAdminSessionToken(adminToken)returns valid; redirect toreturnTo ?? '/' - No admin session — render
<HandoffLauncher>with:- Eyebrow: "Oshun · Operations"
- Heading: "Privileged handoff"
- Body: explanation that admin cockpit is entered through explicit privileged handoff from consumer
hasCustomerSessionflag (fromOSHUN_CONSUMER_SESSION_COOKIE_NAMEpresence)requestId(fromx-request-idheader) for support reference
-
returnToquery param — sanitized viasanitizeReturnTo(verify the rules — likely path-only, no protocol/host) -
reasonquery param — surfaced for the operator to see why they hit handoff
The handoff itself is an out-of-band action (likely a back-channel admin login or a one-time link). The page describes the flow but the admin cookie is set by a separate endpoint (verify which).
Sign-out#
The admin app does not have a dedicated sign-out route in
apps/oshun/admin/src/app. Sign-out is presumably handled by:
- Deleting
OSHUN_ADMIN_SESSION_COOKIE_NAMEvia an API route (verifyapps/oshun/admin/src/app/api/admin/*) - OR a header action wired through the studio governance flow
Open question: where does the operator sign out from? Flag in matrix.
Session refresh#
The admin cookie is parsed on every request via parseAdminSessionToken. No
refresh path is visible in session-cookie.ts — token rotation likely happens
out-of-band on each privileged handoff. Open question: does the token expire?
Scopes and workspace access#
Each workspace declares requiredScopes in OSHUN_ADMIN_WORKSPACE_MODEL.
Examples:
dashboard—['admin:*', 'admin:studio']inbox—['admin:*', 'admin:studio']review—['admin:*', 'admin:studio', 'admin:workspace:review']trust-safety—['admin:*', 'admin:studio', 'admin:workspace:moderation']incidents—['admin:*', 'admin:studio', 'admin:workspace:incident']personas—['admin:*', 'admin:studio', 'admin:workspace:persona']models—['admin:*', 'admin:studio', 'admin:workspace:model']editorial—['admin:*', 'admin:studio', 'admin:workspace:editorial']research-integrity—['admin:*', 'admin:studio', 'admin:workspace:research-integrity']rights—['admin:*', 'admin:studio', 'admin:workspace:rights']support—['admin:*', 'admin:studio', 'admin:workspace:support']privacy—['admin:*', 'admin:studio', 'admin:workspace:privacy']policy—['admin:*', 'admin:studio', 'admin:workspace:policy']lilith—['admin:*', 'admin:studio', 'admin:workspace:lilith']
admin:* is the superuser scope; admin:studio is the broad studio-operator
scope; workspace-specific scopes (admin:workspace:*) allow finer-grained
delegation. canEnterAdminWorkspace(scopes, workspaceId) returns true if any of
the workspace's requiredScopes is present.
Scopes test matrix#
| Operator scopes | Can enter dashboard | Can enter review | Can enter trust-safety |
|---|---|---|---|
['admin:*'] |
✓ | ✓ | ✓ |
['admin:studio'] |
✓ | ✓ | ✓ |
['admin:workspace:review'] |
✗ | ✓ | ✗ |
['admin:workspace:moderation'] |
✗ | ✗ | ✓ |
['admin:workspace:review', 'admin:workspace:moderation'] |
✗ | ✓ | ✓ |
[] |
✗ | ✗ | ✗ |
The above is derived from how the requiredScopes arrays are written — verify
with the canonical canEnterAdminWorkspace test suite at
libs/oshun/navigation/src/admin-ia.test.ts.
Unauthorized page (/unauthorized)#
apps/oshun/admin/src/app/unauthorized/page.tsx
Three known reasons (from REASON_COPY):
-
missing-session— "Admin session required" heading; body tells operator to use privileged handoff and that customer sessions cannot enter admin routes -
invalid-session— "Admin session expired or invalid" heading; body tells operator to request a new privileged handoff -
forbidden-workspace— "Workspace access denied" heading; body tells operator their role doesn't grant the workspace scope
returnTo query param is preserved so the operator can resume after handoff.
Cross-references#
- 02-routing-layouts.md — middleware that enforces the session
- 04-workspace-pattern.md — how individual pages enforce scope after middleware passes
- V1 PWA equivalent:
../../WALKTHROUGH/shell/04-auth-session.md - Session cookie module:
apps/oshun/admin/src/lib/session-cookie.ts - Server session module:
apps/oshun/admin/src/lib/server-session.ts
Open questions / known gaps#
- Document the upstream service that issues the admin session token after privileged handoff
- Confirm token expiry / refresh policy
- Locate the sign-out path (likely an
/api/admin/*route) - Verify
sanitizeReturnTorules inhandoff/page.tsx - Document how
forbidden-workspaceis triggered — middleware doesn't check scope, so this reason originates from a page or BFF