ADR3 refinement
This commit is contained in:
@@ -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)
|
||||
Reference in New Issue
Block a user