Software Requirements: Authentication & Session¶
Introduced in requirements baseline v1.1 (GAP-01, ADR-0011).
| ID | Requirement | Trace |
|---|---|---|
| REQ-AUTH-001 | All user authentication shall be delegated to an external OIDC provider; LQMS shall not store user passwords or second-factor secrets. | STR-016; ADR-0011 |
| REQ-AUTH-002 | LQMS shall authenticate against any standards-compliant OIDC provider, configured per deployment (e.g. a corporate IdP or a bundled Keycloak). | STR-016; ADR-0011 |
| REQ-AUTH-003 | The web client shall use a server-side session (BFF): LQMS performs the OIDC Authorization Code flow with PKCE and holds tokens server-side; the browser receives only an opaque, httpOnly, Secure, SameSite session cookie. | STR-016; ADR-0011 |
| REQ-AUTH-004 | The session cookie shall be encrypted with a server-held key, httpOnly, Secure and SameSite, carrying no client-readable or client-modifiable identity or authorization claims. LQMS shall keep no server-side session store — the encrypted cookie is self-contained, so any service instance can serve any request (stateless horizontal scaling). |
STR-003, STR-016; ADR-0011, ADR-0028 |
| REQ-AUTH-005 | Sessions shall enforce a configurable idle timeout and absolute maximum lifetime, after which re-authentication is required. | STR-016; ADR-0011 |
| REQ-AUTH-006 | Administrative revocation of access (user deactivation or role removal) shall take effect on the user's next request through per-request re-evaluation of lifecycle status and role assignments; a deactivated user shall be denied on every request. User logout shall clear the session cookie and perform IdP single/back-channel logout where supported. The access-token lifetime shall be short (configurable; target ≤ 5 minutes) to bound the validity window of a compromised cookie, with silent server-side token refresh so users are not forced to re-authenticate within their REQ-AUTH-005 session limits. Rotating the cookie-encryption key shall invalidate all outstanding cookies (global revocation). The residual risk that a compromised cookie remains usable until access-token expiry is accepted and recorded (see arc42 §11, RISK-003). | STR-016; ADR-0011, ADR-0028 |
| REQ-AUTH-007 | State-changing requests shall be protected against CSRF (SameSite plus an anti-CSRF token or required custom header). | STR-003; ADR-0011 |
| REQ-AUTH-008 | Authentication shall not grant authorization: an authenticated user with no role assignment shall have no access to any scope's data (deny-by-default, RLS-enforced). | STR-003; ADR-0011, ADR-0009 |
| REQ-AUTH-009 | On first successful authentication a user record shall be provisioned (JIT), keyed to a stable IdP subject identifier, to enable later role assignment; provisioning shall grant no access. (realized/refined by ADR-0063: the identity key is the subject alone (unique within the single realm), so provisioning, invite binding, and the bootstrap matcher all look up by subject only; token issuer validation stays pinned, and changing the public host is config-only without orphaning identities.) |
STR-006; ADR-0011, ADR-0063 |
| REQ-AUTH-010 | On each authenticated request LQMS shall resolve the user's authorized scope set from role assignments and apply it as the RLS context (lqms.authorized_scope_ids) while connecting as the RLS-subject role lqms_app. |
STR-003; ADR-0011, ADR-0009 |
| REQ-AUTH-011 | API clients shall authenticate by OAuth2 bearer token validated against the configured OIDC provider — signature/JWKS, issuer and audience — and shall be subject to the same authorization and RLS as a browser session. LQMS shall accept only tokens that resolve to a PERSON: the token shall carry the stable subject and an email claim, and a token carrying no email — the shape an OAuth2 client-credentials / service-account grant returns — shall be refused at provisioning rather than bound to an identity. (Rewritten 2026-08-21. The previous text promised machine/API client authentication by client credentials, including future MCP; the code has never offered it — AuthenticatedUserService.provisionAndResolve requires an email claim on every request, ahead of any subject-only branch, so a service-account token cannot authenticate at all. The row nevertheless read verified, on a real-provider test that imports a realm whose user carries an email claim BECAUSE the service demands one: it worked around the limitation instead of covering it. That citation was removed and must not be re-added — see the scope-limit note in KeycloakIntegrationTest. Decision (Nicolas, 2026-08-21): rewrite the requirement to what LQMS actually promises rather than build a subject-only provisioning branch, since nothing today issues a machine token and the branch would be unverified code for a hypothetical. Machine/MCP client-credentials access is therefore OUT of scope and requires its own ADR before it is offered.) |
STR-013; ADR-0011, ADR-0005 |