ADR3 refinement

This commit is contained in:
2026-11-12 10:24:10 +01:00
parent dd8f0ce186
commit 39a3f1379c
3 changed files with 266 additions and 21 deletions

View File

@@ -0,0 +1,222 @@
**ID:** ADR3 \
**Title:** Shared identity and application authorization \
**Supersedes:** - \
**Status:** REFINED \
**Expiration Date:** Six months after approval; record the calendar date upon manual approval.
## Context
Agile Dancers needs authenticated access so that private school data is available
only to authorized people. Initially, users are school owners and invited staff.
The design must accommodate teachers, students, and parents later without
requiring their permissions to be designed now.
A person may belong to multiple schools, with different permissions in each.
Future tools must be able to use the same identity, although shared login across
multiple deployed applications is not an immediate requirement. Authentication,
application admission, and access to school data are separate responsibilities.
This decision applies across the application landscape when systems introduce
protected user access. Agile Dancers is the first consumer. Waterpolo Coaching
does not require immediate integration.
There is no budget for paid identity services. Authentication must be self-hosted
and must allow accounts provided by the landscape without requiring an external
Google, Microsoft, or similar account.
The intended host is the existing Synology DS224+, with a four-core Intel Celeron
J4125 and 18 GB RAM, including a 16 GB expansion recognized and verified by the
maintainer. This exceeds Synology's published supported memory maximum. Actual
spare capacity alongside existing workloads has not been measured for identity
hosting. Product sizing guidance is a starting point rather than evidence of
performance on this NAS.
## Decisions
### Shared identity and ownership
Use self-hosted Keycloak as the shared identity provider. Keycloak owns identities,
credentials, authentication factors, and application admission. Applications must
not implement their own password storage or credential verification. Users need
not have an external identity provider account. External sign-in may be considered
later; it is not required initially.
Manage Keycloak deployment configuration, upgrades, and recovery instructions in
a dedicated identity infrastructure repository. Its name remains follow-up work.
Keep secrets outside version control. Applications own their integrations and
runtime configuration. Landscape owns this ADR and the system map; reusable build
resources belong to engineering, consistent with ADR1.
Target the Synology for the initial deployment. Validate startup, normal operation,
and login bursts alongside existing NAS workloads before putting Keycloak into
use. Start capacity planning with Keycloak's documented 2 GB container memory
limit for small production deployments, allowing additional database resources.
This is an initial planning allocation, not a measured consumption guarantee.
### Protocol and browser integration
Use OpenID Connect as the default identity integration protocol. For interactive
browser login, use Authorization Code with PKCE. Redirect users to Keycloak for
authentication. Do not use the implicit or resource owner password credentials
flows.
For browser applications, use a Backend for Frontend pattern: the application
backend completes the protocol exchange and keeps OAuth tokens on the server.
The browser receives a Secure, HttpOnly session cookie. Protect cookie-based
requests against CSRF. This functionality may reside in an application's existing
backend; it does not require a separate deployment.
Validate tokens with established framework support, including signature, issuer,
audience, and lifetime. APIs accept appropriate access tokens, not ID tokens as
API credentials. Local JWT validation using the provider's public keys does not
require a Keycloak request for every API call.
Backend-held tokens reduce credential extraction through malicious browser
scripts. They do not prevent malicious scripts from making requests through an
active browser session; applications still need browser security protections.
### Authentication and recovery
Require MFA for all protected application users. Support password plus an
authenticator code (TOTP), or a passkey configured to require user verification.
Configure Keycloak to enforce these authentication requirements.
Provide recovery codes as the normal fallback. If all authenticators and recovery
codes are lost, the maintainer performs exceptional manual recovery after identity
verification. Email password reset alone must not remove MFA. Define the detailed
identity-verification and recovery procedure before use.
### Application admission and domain authorization
An identity in Keycloak does not automatically grant access to every application.
Require an explicit Agile Dancers admission entitlement in Keycloak. Enforce
admission in the backend, including protected API access; hiding frontend routes
or application links is insufficient.
Agile Dancers owns school memberships, school roles, and school-specific
permissions. One identity may have multiple school memberships with different
permissions. Enforce authorization on the backend for every protected operation
and its school context. An authenticated identity or application admission alone
does not grant school data access.
Other applications own their own domain permissions. If several tools later need
shared school membership semantics, define an explicit contract or separately
owned capability. Shared identity does not imply shared membership storage.
### Provisioning and revocation
The maintainer provisions each school and its first owner. Owners may invite
staff. A controlled provisioning workflow coordinates application admission in
Keycloak and membership in Agile Dancers for an existing or new identity. School
owners receive no Keycloak administration access.
Design provisioning and removal for partial failures, safe retries, and recovery.
An incomplete workflow must not grant school access without the required
admission and membership. Detailed workflow contracts and mechanics are follow-up
implementation work.
Removing a school membership must deny access to that school's data on subsequent
requests, even if updating Keycloak fails. Preserve other school memberships.
When the last Agile Dancers school membership is removed, revoke Agile Dancers
admission as well. Preserve the shared identity and access to other tools.
Allow a maximum five-minute delay before application admission revocation affects
existing access credentials. Token lifetime, clock tolerance, refresh behavior,
and backend session handling together must enforce that bound. A longer-lived
browser session must not bypass it. School membership revocation retains the
immediate behavior described above.
### Adoption and review
Implement first in Agile Dancers. Other tools adopt this approach when they
introduce protected user access; no immediate Waterpolo Coaching integration is
required. Preserve the ability to add broader user audiences later.
Review six months after approval. The review date triggers reevaluation rather
than automatic expiry. REFINED records the agreed proposal; approval is a
separate manual action.
## Options considered
### Identity architecture
| Option | Pros | Cons | Outcome |
| --- | --- | --- | --- |
| Existing shared identity product | Shared identity across tools; established authentication and account-management capabilities; avoids building a login product. | Adds an operational dependency, database, configuration, updates, and recovery work. | Chosen. |
| Authentication within each application using established libraries | Fewer services initially; direct application control over the experience. | Duplicates account lifecycle work; separate accounts by default; shared identity requires later migration or federation. | Not chosen because shared identity across future tools is desired. |
| Custom shared identity service using established libraries | Shared identity with full control over behavior. | Makes protocol integration, account recovery, sessions, and security maintenance a custom product responsibility. | Not chosen because the development and maintenance burden is unjustified. |
### Self-hosted product
| Option | Pros | Cons | Outcome |
| --- | --- | --- | --- |
| Keycloak | Supports OIDC with PKCE, local accounts, passkeys, MFA, shared login, and future external identity integration. | Requires service and database maintenance; resource suitability on the NAS still needs measurement. | Chosen for capability fit; validate NAS capacity before use. |
| authentik | Supports OIDC with PKCE, passkeys, and TOTP; flexible application integration. | Requires server, worker, and PostgreSQL operation; open-source and paid feature boundaries need attention. Its documented host minimum does not establish a lower footprint than Keycloak. | Credible alternative, but no demonstrated resource advantage justifies preferring it here. |
Keycloak documents a 2 GB container limit recommendation for small production
installations. authentik documents a host minimum of two CPU cores and 2 GB RAM.
These figures describe different scopes and are not a comparative benchmark.
### Authorization ownership
| Option | Pros | Cons | Outcome |
| --- | --- | --- | --- |
| Keycloak admission plus application-owned domain permissions | Central admission control; school rules stay with school data; applications can evolve independently. | Requires coordinated admission and membership workflows, including failure recovery. | Chosen. |
| Centralize school memberships and permissions in Keycloak | Central administration and potential reuse across tools. | Couples domain changes to identity configuration; applications still need data-access enforcement. | Not chosen for domain authorization. |
### Browser integration
| Option | Pros | Cons | Outcome |
| --- | --- | --- | --- |
| Backend-held tokens with a browser session cookie | Keeps OAuth tokens unavailable to browser scripts; uses the existing backend. | Adds session lifecycle management and CSRF protection; malicious scripts can still act through the browser. | Chosen. |
| Frontend-held tokens with Authorization Code and PKCE | Direct frontend-to-API integration; avoids backend login sessions. | Malicious application scripts can steal valid tokens for reuse elsewhere; PKCE does not prevent that theft. | Not chosen for browser applications. |
OIDC provides the required identity integration. SAML is not required by current
consumers; this ADR does not declare SAML obsolete.
## Consequences
- Create the dedicated identity infrastructure repository and specify deployment,
upgrade, backup, restore, and manual recovery procedures. Creating documentation
does not authorize production deployment.
- Validate NAS resource usage before use, including database overhead and competing
workloads. Implementation configuration and measured validation evidence belong
in the owning repositories.
- Integrate Agile Dancers with backend-managed OIDC login, protected sessions,
application admission enforcement, and school authorization.
- Specify membership storage and school permission rules for owners and invited
staff. Broader audiences are future work within the agreed identity boundaries.
- Implement controlled invitations and coordinated admission removal. Define
failure recovery, retries, and reconciliation without weakening school isolation.
- Validate mandatory MFA, passkey user verification, recovery protection, immediate
school membership revocation, and the five-minute admission revocation bound.
- Define session renewal, logout, and identity-provider outage behavior in the
consuming application specification. Failure behavior must preserve the agreed
authorization and revocation bounds.
- Shared identity introduces a common dependency: Keycloak outages can affect login
and session renewal across integrated tools. NAS and database colocation retain
shared infrastructure failure points.
- Maintain systems.md as the planned service becomes an implemented system and
repositories and responsibilities become concrete.
- Record the absolute review date upon manual approval. This ADR does not itself
create repositories, provision accounts, or deploy services.
## References
Consulted on 2026-11-10:
- [OIDC Core](https://openid.net/specs/openid-connect-core-1_0.html)
- [RFC 9700: OAuth 2.0 Security Best Current Practice](https://www.rfc-editor.org/info/rfc9700/)
- [RFC 10017: OAuth 2.0 for Browser-Based Applications](https://www.ietf.org/ietf-ftp/rfc/rfc10017.html)
- [Keycloak overview](https://www.keycloak.org/)
- [Keycloak administration guide](https://www.keycloak.org/docs/latest/server_admin/)
- [Keycloak OIDC integration](https://www.keycloak.org/securing-apps/oidc-layers)
- [Keycloak container memory configuration](https://www.keycloak.org/server/containers)
- [Keycloak resource sizing](https://www.keycloak.org/high-availability/single-cluster/concepts-memory-and-cpu-sizing)
- [Keycloak production configuration](https://www.keycloak.org/server/configuration-production)
- [authentik installation requirements](https://docs.goauthentik.io/install-config/install/docker-compose/)
- [authentik components](https://docs.goauthentik.io/install-config/first-steps/)
- [authentik OIDC and PKCE](https://docs.goauthentik.io/add-secure-apps/providers/oauth2/)
- [authentik authenticators](https://docs.goauthentik.io/users-sources/user/user-interface/)
- [authentik enterprise distinction](https://docs.goauthentik.io/enterprise/)
- [Synology DS224+ specifications](https://www.synology.com/en-us/products/DS224%2B)