Story AUTH-009: Enterprise identity federation — per-Organization IdP brokering (OIDC + SAML)¶
Module: identity Slice: arch §0.1 AUTH-005 (federation) + §0.3 (IdP brokering per org) Side: [BACKEND] Version target: V0 — v0.0.5 Priority: 9 Depends on: AUTH-003 (Keycloak Organizations must exist), AUTH-002 (ROPC login as fallback) Can develop concurrently with: AUTH-008 Merge order: After AUTH-003 Estimated complexity: L PRD User Stories: AUTH-ADM-08 (per-Organization IdP brokering) Wireframe: N/A — backend only (configured by OPS via the Keycloak Admin REST API; no AUTH-owned UI — design §15 confirms no SSO screen)
Objective¶
v0.0.5 targets enterprise tenants (e.g. NSIA) who want their staff to log in with their own corporate identity provider instead of a separate Papillon password. This story links a tenant's Keycloak Organization to its external IdP (OIDC or SAML), routes a user to the right IdP based on their email domain, and maps the federated user into the correct per-Organization groups so the tenant_id claim is still emitted.
Backend Scope¶
Entities¶
No new AUTH tables. Configuration lives in Keycloak (Organization-level IdP brokering links + mappers). The users projection row is created/linked for federated users as for local users.
Service Layer¶
- OPS configures an IdP brokering link at the Organization level via the Keycloak Admin REST API:
POST /admin/realms/papillon/organizations/{org}/identity-providers(arch §C.3 / §10.1). AUTH surfaces any Keycloak validation error back to the caller. - Domain-based discovery: a user typing an email matching the tenant's verified domain(s) is redirected to that tenant's IdP at the
/loginstep. Users without a federated domain continue to use local ROPC (AUTH-002). - Group / claim mapping: Keycloak IdP mappers (Hardcoded Group, Advanced Claim to Group) auto-place the federated user into per-Organization groups matching their role; the
tenant_idJWT claim is emitted from the Organization id even when the user comes from a federated IdP (arch §0.3). - Fallback: if the IdP brokering link is misconfigured (invalid SAML metadata, unreachable OIDC discovery endpoint), AUTH surfaces the Keycloak validation error and falls back to local ROPC; OPS retries.
- A tenant with divergent password / MFA policy may be carved out to a dedicated realm (hybrid). This carve-out is a manual OPS runbook, not automated in V0 (arch §0.3).
API Endpoints¶
No new application-plane endpoint. IdP links are managed through the Keycloak Admin REST API (OPS-driven). The operator login page reuses the existing /login route with domain-based redirect.
Validation Rules¶
- IdP brokering is configured per Organization (one tenant = one Organization).
- A federated assertion must yield the
tenant_idclaim from the Organization id and the correct group mapping for the user's role. - v0.0.0–v0.0.4 remain ROPC-only against the shared realm; brokering is only available from v0.0.5.
Multi-Tenant Considerations¶
Each tenant's Organization brokers only its own IdP. A federated user is always pinned to their tenant via Organization membership; the emitted tenant_id claim drives all downstream tenant isolation exactly as for ROPC users. No cross-tenant identity leakage between Organizations.
Audit & Logging¶
- Federated logins reuse
operator_login_attempt/operator_session_started(mfa_factor reflects the federated path). Misconfiguration surfaced to OPS is logged.
Frontend Scope¶
N/A — backend / Keycloak configuration. The /login page (AUTH-002) gains domain-based redirect behaviour, but there is no new AUTH-owned SSO screen (design §15 confirms none is specified).
UI States (ALL REQUIRED)¶
N/A — backend only (the redirect to the external IdP is handled by Keycloak).
Acceptance Criteria¶
AC-001: Email-domain match redirects to the tenant's IdP
Given a tenant Organization with an IdP brokering link and verified domain(s) configured
When a user enters an email matching one of those domains at /login
Then they are redirected to the tenant's IdP (OIDC or SAML)
And a user with a non-federated domain continues with local ROPC
AC-002: Successful federated assertion maps the user and emits tenant_id
Given a federated user authenticates successfully at their IdP
When Keycloak returns the assertion
Then IdP mappers place the user into the per-Organization groups matching their role
And the issued JWT carries the tenant_id claim derived from the Organization id
AC-003: Misconfigured IdP link surfaces an error and falls back to ROPC
Given OPS commits an IdP brokering link with invalid SAML metadata or an unreachable OIDC discovery endpoint
When the change is applied
Then AUTH surfaces the Keycloak validation error in the platform-admin console
And login falls back to local ROPC so the tenant is not locked out
Compliance Rules¶
- No federation-specific compliance article in the PRD beyond the general RBAC/realm posture (PRD Topic 9). RBAC + traçabilité = VÉRIFIÉ.
- Note the scope tension (PRD §C.5 lists federated SSO as V3, while §A.3 AUTH-ADM-08 + D-11 + the V0 envelope pull per-Organization brokering forward to v0.0.5). Decompose follows the V0 envelope (v0.0.5). Flagged in the index Open Questions.
Standards & Conventions¶
docs/standards/multi-tenant-model.md(Keycloak Organizations, realm strategy D-11, hybrid carve-out).docs/standards/java-spring-guidelines.md.docs/standards/api-guidelines.md.
Testing Requirements¶
Unit Tests¶
- Domain → IdP resolution picks the correct Organization IdP; unknown domain → ROPC.
Integration Tests¶
- Testcontainers Keycloak with a stub external IdP (OIDC and/or SAML): federated login yields a JWT with the correct tenant_id claim and group mapping.
- Misconfigured link → validation error surfaced + ROPC fallback still works.
- Two Organizations with different IdPs do not leak identities across tenants.
What QA Will Validate¶
- Enterprise users reach their own IdP by email domain; the resulting token is correctly tenant-scoped; a broken IdP config does not lock the tenant out (ROPC fallback); non-enterprise tenants are unaffected.
Out of Scope¶
- Realm-per-tenant automation (hybrid carve-out) — manual OPS runbook in V0; automation is V2+.
- FGAP-based per-Organization admin delegation (Keycloak 26.7) — interim handled by a thin OP-module admin UI (TV-09).
- SCIM / automated user provisioning from the IdP — not in V0.
- Customer-side authentication is unaffected (signed link only).
Definition of Done¶
- [ ] Per-Organization OIDC + SAML IdP brokering configurable via Keycloak Admin REST API
- [ ] Email-domain discovery redirects to the right IdP; non-federated users use ROPC
- [ ] Federated assertion maps groups and emits the tenant_id claim from the Organization id
- [ ] Misconfigured IdP surfaces an error and falls back to ROPC
- [ ] Unit + integration tests written and passing (incl. cross-Organization isolation)
- [ ] Tenant isolation verified (Organization membership pins tenant_id)
- [ ] No silent failures (misconfig is surfaced, never silently breaks login)