Skip to content

docs(auth): design product-branded login themes + native multi-realm direction - #20

Merged
swimmesberger merged 1 commit into
mainfrom
wt/product-idp-login-pages-57f34a
Aug 10, 2026
Merged

docs(auth): design product-branded login themes + native multi-realm direction#20
swimmesberger merged 1 commit into
mainfrom
wt/product-idp-login-pages-57f34a

Conversation

@swimmesberger

Copy link
Copy Markdown
Owner

What

Design-only change to docs/central-auth/design.md — no code. Captures the design conversation from 2026-08-10 on product-specific IdP login pages before it evaporates.

  • New §12 — Product-branded login pages & themes. A user hitting a protected product app experiences the product's login (LAF and login domain), never Watchtower's. Anchored on Keycloakify's contract (theme owns the chrome, IdP owns the flow) combined with Auth0's trust model (runtime application, gated on operator access). Key decisions:
    • Branding is server-resolved and keyed by Host only — preserves the existing invariant that nothing derived from redirect_uri is ever rendered, and avoids the enumeration leak a redirect-uri-keyed lookup would create.
    • Three-rung ladder: branding tokens on StackTemplate → per-category auth hosts → runtime theme bundles.
    • Themes ship as OCI images used as delivery vehicles only (single layer, /theme/index.html + theme.json with kernelApiVersion, digest-pinned, hostile-archive extraction) — pulled and extracted by Watchtower, never run. A running theme container is explicitly rejected (login critical path, loss of kernel/CSP injection point).
    • LoginTheme library separate from assignment; resolution chain route → template → realm default → built-in, always failing closed to the built-in page.
    • Custom themes require a per-category auth host (blast radius = one origin) and a strict self-only CSP.
  • New §13 — Native multi-realm direction. Watchtower must grow multiple realms itself; external IdPs (Keycloak/Entra) become a per-realm federation feature for customers who already run an IdP — not Watchtower's exit ramp. Records the model shape (Realm, realm-scoped uniqueness, SSO scope = auth host) and the three seams to keep open now without building realms yet.
  • §2.7 rewritten — the old "delegate to Keycloak" exclusion no longer matches the strategy; only the protocol-scope exclusion (no authorize endpoint/client registry yet) survives. Status line and §2.8 staging updated with pointers.

Why

The product-central-management direction needs products to present their own login experience without users realizing they hit a shared gate. This PR pins down how to do that without weakening the login page's security invariants, and records the strategic inversion on Keycloak before future auth work bakes in single-realm assumptions.

Reviewer notes

  • Everything here is designed, not implemented — the sections are explicitly marked as such.
  • The most consequential call to sanity-check is §13's framing inversion of §2.7, since it redirects future auth roadmap.
  • Second-most: the "full trust" position on theme JS credential visibility (§12.2, dial recorded with the iframe-isolation upgrade path).

…direction

Adds two designed-not-implemented sections to the central-auth design:

- §12 Product-branded login pages & themes: server-resolved host-keyed
  branding, per-category auth hosts, runtime OCI theme bundles (pulled and
  extracted, never run) with an auth-kernel/CSP contract, theme library with
  route -> template -> realm -> built-in resolution, and management-API
  application by product stacks.
- §13 Native multi-realm direction: Watchtower grows realms itself; external
  IdPs become per-realm federation for customers who already run one, not the
  exit ramp. Records the seams to keep open now (realm-scopable uniqueness,
  extensible token issuer/claims, per-population settings hung on realm).

Rewrites the §2.7 "delegate to Keycloak" exclusion to match the inverted
framing and threads pointers through the status line and §2.8 staging.
@swimmesberger
swimmesberger merged commit 3a9b700 into main Aug 10, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant