Skip to content

Central identity: Watchtower as OIDC provider + tenant registry (realms, invitations, device/session management, MFA) #31

Description

@swimmesberger

Goal

Make Watchtower the central management platform and identity provider for a family of per-customer application deployments (single-tenant Elarion apps, one deployment + database + subdomain per customer), so those applications can deliver the auth features that were deliberately deferred out of the instances: device/session management (list signed-in devices + revoke), MFA, and SSO-backed switching between instances.

The downstream product's architecture decisions (private repo) concluded that these features must not be built per-instance: its cookie auth has no server-side session to list or revoke, and in-app TOTP would be discarded once authentication moves to a central IdP. Watchtower's central-authorization work (Phase 1: local users, revocable DB sessions, forward-auth with ES256 JWT/JWKS, per-route policy, audit rows; Phase 2 planned in #18) is the natural home. This issue collects everything Watchtower must provide for that plan to proceed. It complements #18 — overlaps are called out per requirement.

Note the directional difference from #18 §1: there, Watchtower is an OIDC relying party toward an upstream IdP. Here, Watchtower must additionally act as an OIDC provider for downstream tenant applications. The two roles compose (Watchtower may broker an upstream IdP while remaining the issuer for its tenants), but they are distinct pieces of work.

Requirements

R1 — OIDC authorization server (provider role)

  • Standard OpenID Connect authorization-code flow (+ PKCE) with Watchtower as the issuer; one confidential client registration per tenant instance (each instance runs on its own subdomain with its own backend).
  • Build on OpenIddict on top of ASP.NET Core Identity rather than hand-rolling the protocol. Watchtower already runs ASP.NET Core Identity core (security stamps etc., per Phase 1), so this is an extension, not a rebuild.
  • Discovery document, JWKS, token endpoint, end-session/logout endpoint per issuer (see R2 for multi-issuer).
  • Refresh tokens with sliding expiration are required — they are what makes persistent login ("stay signed in") work and what gives sessions a server-side identity to list and revoke (R6).

R2 — Realms by population, never by tenant

  • Three realms: central management (operator staff — effectively Watchtower's existing local users), tenant-app staff (professional users across all tenant instances — one identity, many tenants), and end customers (self-service, high volume).
  • A realm per tenant is explicitly rejected: one person must be able to reach several tenants with one identity and hold a different role in each.
  • Non-negotiable: a separate user store per realm — the end-customer/staff boundary must be real, not a flag on a shared table. Separate issuer paths and per-realm signing keys; whether that is one deployment or several is a deployment detail (start with one).
  • Self-registration, if ever enabled, exists only in the end-customer realm and must be unable to touch the staff stores.
  • Per-realm policy knobs: MFA enforcement (R7), token/session lifetimes, password policy.

R3 — Claims contract: credentials only

  • Tokens/userinfo carry the stable subject, e-mail, and e-mail-verified state. Nothing else.
  • No names, no profile data, no roles, no permissions: authorization vocabulary is generated per application/version and stays entirely in the instance. The instance maps issuer + sub to its local account row (standard user_logins binding) and keeps role assignment local.
  • Privacy consequence (the reason this matters): the central platform becomes custodian of end-customer credentials, never of end-customer data — keeps each tenant's data isolation intact and narrows the contractual (data-processing agreement) scope.

R4 — Tenant registry and membership

This is the stated justification for building on Watchtower instead of adopting Keycloak: the IdP doubles as the tenant registry.

R5 — Invitation-first provisioning API (never just-in-time)

  • JIT provisioning is rejected: access is deny-by-default and the tenant administrator stays in control.
  • Flow to support: tenant instance invites by e-mail → instance calls Watchtower to register the membership (pending) → on the person's first sign-in, Watchtower asserts the e-mail is verified, the instance matches its pending local row by e-mail once, and thereafter the binding is by subject only (e-mail becomes display data — e-mail matching after binding is an account-takeover path).
  • Watchtower needs: authenticated server-to-server API for instances (register/revoke membership, query binding state), e-mail verification enforcement, and the failure mode "invitation could not be registered centrally" surfaced to the instance rather than swallowed.
  • Requires outbound e-mail capability in Watchtower (invites, verification, password reset), configurable like the rest of the platform (SMTP settings as an operator-configured port).

R6 — Device/session management (the headline feature)

  • Persisted, per-user sessions/authorizations (OpenIddict authorizations + refresh tokens; Phase 1's revocable DB sessions extended to the provider role) with recorded metadata: created/last-used timestamps, IP, user agent / rough device label.
  • Self-service "signed-in devices" page per user (all realms): list active sessions/devices, revoke one, revoke all others.
  • Admin-side: view/revoke sessions per user; central deactivation of an identity ends access to all tenants at once (the second off-boarding lever; local deactivation in one instance remains the first).
  • Revocation must actually bite within a bounded time on instances: short access-token lifetimes plus refresh-token revocation as the baseline; back-channel logout or introspection optional hardening.
  • Persistent-login policy per realm (e.g. staff 30 days sliding, configurable).

R7 — MFA

R8 — Account lifecycle, audit, and admin surface

  • Centralized: password reset, e-mail change with re-verification, deactivation, login history. Per-realm admin UI for the operator.
  • Audit: Phase 1 writes AuthEvent rows but has no viewing surface (Central authorization Phase 2: OIDC upstream, groups, template inheritance, TOTP #18 follow-up) — required here, since off-boarding and session revocation across tenants must be auditable.
  • Login history remains additionally visible inside each instance (it already exists there today; instances keep recording their own logins on token sign-in).

R9 — Availability and break-glass

The IdP becomes a single point of failure across every tenant. Required mitigations, designed up front:

  • Token lifetimes chosen so a short IdP outage does not sign everyone out mid-work.
  • A break-glass local administrator login per tenant instance that works with the IdP down (the instances keep ASP.NET Identity; the local-password path is retained for exactly this).
  • Watchtower's own recovery path (RESETPASSWORD break-glass) extended to cover the provider role; backup/restore story for the identity stores.

R10 — Migration support

  • Instances will run cookie login and OIDC login in parallel during migration, enabling per-instance, per-realm cutover.
  • Rollout order that keeps risk low: staff realm on one pilot instance → staff everywhere (unlocks SSO instance switching) → end-customer realm last.
  • Existing users are migrated invitation-style: pre-registered membership + one-time verified-e-mail match on first central sign-in (same mechanism as R5, so no bulk credential migration).

Out of scope

  • Anything role/permission-shaped in tokens (stays in the applications).
  • Profile/domain data in the IdP.
  • Per-tenant realms; per-tenant IdPs, SCIM, service tokens (Central authorization Phase 2: OIDC upstream, groups, template inheritance, TOTP #18's Phase 3 note).
  • The instance-side work (external-login binding, directory adapter, parallel login paths, break-glass UX) — tracked in the downstream product's own (private) issues; listed here only where it constrains Watchtower's API surface.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions