Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
8.8 KiB
8.8 KiB
PRD — EE+CE Domain-Scoped SSO Takeover and Domain Approval
- Slug:
ee-ce-domain-scoped-sso-takeover - Date:
2026-03-03 - Status: Draft
Summary
Extend MSP domain-scoped SSO discovery so it works cleanly across both Enterprise Edition (EE, multi-tenant) and Community Edition (CE, on-prem), while enabling customer-owned Google/Microsoft providers for claimed domains.
Key behavior target:
- MSP login in both EE and CE uses email-domain discovery to decide which SSO providers are eligible.
- In EE, tenant takeover of a domain requires domain ownership verification before tenant providers are used.
- In CE, domain registration is advisory (no mandatory ownership verification gate).
- For domains not covered by an approved/eligible tenant registration, discovery falls back to Nine Minds standard app-level SSO provider configuration.
Problem
Domain-scoped SSO discovery exists, but we need a complete product model for customer-owned provider takeover that is safe and operationally clear:
- EE needs a domain ownership approval process so tenants cannot claim domains they do not control.
- CE needs login-screen parity using the same discovery mechanism, but with simpler (advisory) domain registration.
- Unmanaged or not-yet-approved domains must reliably route to Nine Minds default SSO providers.
- This must preserve anti-enumeration behavior and avoid regressions to existing
/auth/msp/signinflows.
Goals
- Support domain-scoped SSO routing in both EE and CE on
/auth/msp/signin. - Add EE-only domain ownership verification before tenant domain takeover is active.
- Keep CE domain registration advisory, per product decision, while still supporting discovery-driven login UX.
- Route unmanaged/unapproved domains to Nine Minds default SSO providers.
- Preserve anti-enumeration posture and existing credentials login behavior.
Non-goals
- Changing client portal sign-in behavior.
- Introducing new IdPs beyond Google and Microsoft in this phase.
- Redesigning OAuth account linking or bulk SSO assignment semantics.
- Introducing mandatory custom hosted login domains.
Users and Primary Flows
Personas
- MSP internal user signing into
/auth/msp/signin. - EE tenant admin managing SSO domains and provider credentials.
- CE admin managing advisory domain registrations.
Primary Flow A — EE Verified Domain Takeover
- User enters
user@acme.comon MSP sign-in. - Discovery resolves
acme.comto a verified EE tenant claim. - Discovery enables only providers configured by that tenant.
- Resolver enforces allow-list and uses tenant credentials.
- OAuth callback proceeds using existing mapping behavior.
Primary Flow B — EE Domain Not Eligible for Takeover
- User enters email for a domain with claim state
pending,rejected,revoked, or ambiguous ownership. - Discovery does not use tenant takeover.
- Discovery returns app-level (Nine Minds) providers if configured.
- Resolver uses app-level source only.
Primary Flow C — CE Advisory Registered Domain
- User enters email for a CE advisory-registered domain.
- Discovery can use tenant/domain context (no ownership verification requirement).
- Discovery enables eligible providers and resolver proceeds accordingly.
Primary Flow D — Domain Not Registered in Either Edition
- User enters email for unregistered/unresolved domain.
- Discovery returns Nine Minds app-level provider availability.
- Resolver uses app-level source if available.
Primary Flow E — Credentials Login
- User signs in with email/password.
- Existing credentials flow remains unchanged.
UX / UI Notes
- MSP login keeps current layout in EE and CE.
- SSO buttons remain disabled until a syntactically valid email is entered.
- Eligible providers are controlled only by discovery response.
- EE settings expose domain claim lifecycle with verification guidance and status.
- CE settings expose advisory domain registration with clear copy that ownership verification is not enforced.
- UX messaging for fallback should be neutral and non-enumerating.
Requirements
Functional Requirements
- Support domain claim lifecycle states suitable for EE verification and CE advisory behavior.
- Add EE-only domain verification challenge generation and validation workflow.
- Allow EE tenant admins to request, verify, refresh, and revoke domain claims in settings.
- Preserve existing tenant domain management capabilities while adding lifecycle metadata.
- Apply conflict policy so only one EE tenant can hold an active verified takeover for a domain.
- Update discovery logic to evaluate edition + claim lifecycle before enabling tenant takeover.
- In EE, tenant takeover is allowed only for verified, non-ambiguous claims.
- In CE, domain registration remains advisory (no verification gate), as a deliberate product rule.
- For domains without eligible takeover, discovery returns app-level Nine Minds provider options.
- Update CE MSP SSO login wiring to use discovery/resolver mechanism (not static/null SSO UI).
- Keep discovery and resolver response contracts invariant and anti-enumerating.
- Keep resolver allow-list enforcement and signed cookie checks intact with lifecycle-aware source validation.
- Keep credentials login and client-portal auth behavior unchanged.
- Preserve
/auth/msp/signinroute and callbackUrl passthrough behavior.
Non-functional Requirements
- Anti-enumeration: no pre-auth behavior may reveal specific user existence.
- Security: EE ownership verification data must be signed/validated and never expose secrets.
- Backward compatibility: existing tenants/domains continue functioning with explicit migration defaults.
- Performance: discovery remains bounded and low-latency on login path.
Data / API / Integrations
Data model
Add lifecycle support to SSO login-domain persistence, including:
- Domain claim status (
advisory,pending,verified,rejected,revoked, or equivalent normalized states) - Verification metadata for EE claims (challenge id/token hash, verification timestamps, actor metadata)
- Conflict/ownership metadata needed to enforce single verified owner in EE
Optional supporting table may be introduced for domain verification challenges/history if needed.
Endpoints / actions
- Keep
POST /api/auth/msp/sso/discoveras the MSP pre-auth discovery endpoint. - Keep
POST /api/auth/msp/sso/resolveas the gated resolver endpoint. - Add/extend settings server actions for:
- list claims
- request claim
- refresh challenge
- verify ownership (EE)
- revoke claim
Provider routing policy
- EE verified claim + tenant provider credentials => tenant-scoped provider routing.
- EE non-verified/non-eligible claim => app-level Nine Minds provider fallback.
- CE advisory registration may enable tenant-scoped routing; lack of advisory registration falls back to app-level.
Security / Permissions
- Only authorized internal admins can manage claims/verification in settings.
- EE verification must prove domain control before takeover is marked verified.
- Resolver must re-check eligibility at resolve time to avoid stale discovery escalation.
- Discovery and resolver cookies remain signed, short-lived, httpOnly, sameSite-lax.
Observability
Use existing structured logs for:
- discovery source (
tenantvsapp) - claim lifecycle transition events
- resolver source selection outcomes
No new metrics/dashboard project is required in this phase.
Rollout / Migration
- Add schema migration for claim lifecycle and optional challenge storage.
- Backfill existing domain rows to deterministic initial states:
- EE existing domains:
verified_legacy(or equivalent verified-compatible status) - CE existing domains:
advisory
- Keep
/auth/msp/signinand existing links unchanged. - Roll out with EE/CE parity tests for discovery + resolver routing matrix.
Open Questions
- Should EE support automatic periodic re-verification for long-lived verified claims, or manual revoke/re-verify only in this phase?
- For EE verified conflicts, should second claimant fail immediately at request time or only at verify time? (recommend fail at verify with neutral error and conflict context in admin UI)
Acceptance Criteria (Definition of Done)
- EE admins can request, verify, and revoke SSO domain claims.
- CE admins can manage advisory domain registrations.
- MSP login in EE and CE uses domain discovery to enable provider buttons.
- EE tenant takeover occurs only for verified non-ambiguous claims.
- CE advisory mode works without mandatory ownership verification.
- Unmanaged/unapproved domains use Nine Minds app-level provider fallback.
- Resolver enforces discovered allow-list and lifecycle-aware source eligibility with generic failures.
- Credentials and client portal auth flows are unchanged.
/auth/msp/signinand callbackUrl passthrough remain compatible.