feat: add browser auth shell
This commit is contained in:
@@ -155,7 +155,9 @@ elevation — but is disabled by default as of Phase 5D pass 1, below. See
|
||||
[ADR 0011](decisions/0011-identity-http-transport-and-public-enrollment.md) and
|
||||
[the API guide](../development/api.md), and
|
||||
[the identity development guide](../development/identity.md) for the underlying schema and
|
||||
contracts. It is now possible to publicly register, sign in, resolve a principal, and sign out.
|
||||
contracts. Email/password sign-in, principal resolution, and sign-out are operational. Public
|
||||
registration is available only when explicitly enabled for development/test; production rejects it
|
||||
until verified enrollment and durable shared abuse controls exist.
|
||||
|
||||
Phase 4C is complete: Core's authorization foundation — a schema, evaluator, and store for
|
||||
platform owners, explicit grants, and relationship-derived grants, plus an immutable permission
|
||||
@@ -226,8 +228,8 @@ takes a DOM element and returns an unmount function, so a module's framework and
|
||||
independent.
|
||||
|
||||
The contract lives in `@ekklesia/module-ui-sdk`, a browser-safe shared package with no runtime
|
||||
dependencies, consumed by module authors and hosts alike. Its host context is four members —
|
||||
`moduleId`, `api`, `principal`, `permissions`. Module UI reaches its own backend through
|
||||
dependencies, consumed by module authors and hosts alike. Its host context is five members —
|
||||
`moduleId`, `api`, `principal`, `permissions`, and `realtime`. Module UI reaches its own backend through
|
||||
`api.request(path)` with a path relative to the module's own API root, never by constructing
|
||||
Ekklesia's `/api/v1/modules/<module-id>` prefix, which is what keeps a standalone host possible.
|
||||
Client-side permission hints are presentation only; server-side enforcement remains the sole
|
||||
@@ -244,8 +246,9 @@ option in one `tooling` package so module authors write no build configuration.
|
||||
rather than externalized, keeping `mount()` the ABI and a module artifact hostable by any host;
|
||||
styling is inline style objects only, and a stylesheet import fails the build rather than emitting an
|
||||
asset nothing declares. Building remains an authoring step — Core never builds, and discovery still
|
||||
only validates the artifact a module shipped. The Dashboard shell, a UI runtime, a design system, a
|
||||
stylesheet loading contract, the standalone host, and every feature module remain future work.
|
||||
only validates the artifact a module shipped. At that checkpoint the Dashboard shell and UI runtime
|
||||
were still future work; later Phase 6 passes supplied them. A design system, stylesheet loading
|
||||
contract, standalone host, and every real feature module remain future work.
|
||||
|
||||
**Phase 6B pass 3 makes the browser boundary real and adds the generic host loader.**
|
||||
[ADR 0024](decisions/0024-browser-safe-ui-sdk-and-host-loader.md) removes the UI SDK's last
|
||||
@@ -338,9 +341,9 @@ permission the inventory does; organizing requires the new platform permission
|
||||
shell renders that arrangement and computes none of it.
|
||||
|
||||
**Still not the finished Dashboard.** No editor or drag and drop, no nested folders, no icons, no
|
||||
Dashboard Home or widgets, no design system, and no client routing. A production CSP and a deployment
|
||||
for the built shell, sign-in UI, general asset publication, and the standalone host remain future
|
||||
work.
|
||||
Dashboard Home or widgets, no design system, and no client routing. A production CSP and deployment
|
||||
for the built shell, general asset publication, and the standalone host remain future work. Phase 7B
|
||||
pass 1 later supplies the host-owned sign-in flow described below.
|
||||
Restart-based discovery, explicit operator-invoked migrations, and the trusted compiled-module model
|
||||
are all unchanged.
|
||||
|
||||
@@ -504,3 +507,33 @@ whether routes exist, and installed-manifest changes remain restart-based. Realt
|
||||
object URLs are unchanged and flow through the same portable contracts. Named display variants,
|
||||
targeting, display inventory/management, device/public identity, a standalone host, shared CSS,
|
||||
Announcements migration, and Companion integration remain later work.
|
||||
|
||||
Phase 7B pass 1 closes the Dashboard's browser authentication loop
|
||||
([ADR 0034](decisions/0034-host-owned-browser-authentication.md)). The surface, not a module, owns
|
||||
the email/password form, sign-out control, pending/failure states, and session transitions. Bootstrap
|
||||
stays principal-first: anonymous renders login, authenticated proceeds to protected Dashboard
|
||||
navigation, and an identity infrastructure failure remains a retryable failure rather than a false
|
||||
anonymous result. Successful sign-in is followed by a fresh `/api/v1/principal` resolution before
|
||||
any module mounts; sign-out is followed by the same resolution. Leaving authenticated state removes
|
||||
the Dashboard subtree so the generic loader performs the selected module's normal cleanup, including
|
||||
its realtime subscription teardown.
|
||||
|
||||
The browser posts to Better Auth's existing `/api/auth/sign-in/email` and `/api/auth/sign-out`
|
||||
routes with credentials included. `apps/api` normalizes any body-bearing successful `2xx` email
|
||||
sign-in response to fixed `{"ok":true}` while preserving its status and the HttpOnly `Set-Cookie`;
|
||||
the redundant Better Auth token and user object never reach browser application JavaScript. The
|
||||
token-bearing native `/api/auth/get-session`, `/api/auth/list-sessions`,
|
||||
`/api/auth/update-session`, and `/api/auth/change-password` paths are unavailable behind a sanitized
|
||||
`404`; `/api/v1/principal` is the browser's only supported session read, and password/account
|
||||
management remains out of scope. The cookie remains host-only and exact trusted origins,
|
||||
credentialed CORS, and origin/CSRF checks remain unchanged. Login stays at the current Dashboard URL
|
||||
and accepts no callback or return target, so this pass introduces no redirect sink.
|
||||
|
||||
The five-member module UI context is unchanged; modules receive no auth method, credential, cookie,
|
||||
or session token. Platform-owned bootstrap `401` maps directly to unauthenticated, but module-owned
|
||||
responses are not host session authority: module `401` and `403` both trigger a deduplicated
|
||||
principal revalidation, and only an anonymous result resets authentication and unmounts the module.
|
||||
An authenticated result preserves the response, session, and mounted UI. Display device identity
|
||||
remains deferred and the display bundle gains no Dashboard login. Public Website routing,
|
||||
production Dashboard asset hosting/DNS/TLS/proxy/CSP, enrollment and recovery, shared throttling,
|
||||
and the missing production first-user creation path are also outside this pass.
|
||||
|
||||
Reference in New Issue
Block a user