First half of S-12c (behandel-portal backend), per ADR-0013 (decisions recorded in #84):
BFF multi-realm auth. A second JWT bearer scheme (medewerker) alongside the default digid scheme. On validation it lifts Keycloak's realm_access.roles onto the principal, and a behandelaar policy (medewerker scheme + behandelaar role) gates /behandel/*. Self-service keeps the digid scheme.
Werkbak = Flowable tasks. The domain Werkbak query reads the open Beoordelen tasks (§8.2, S-12b's IUserTaskClient) and enriches each with its aggregate's bsn + status; GET /behandel/werkbak (domain) is proxied by the BFF GET /behandel/werkbak behind the behandelaar policy. The read projection stays the anonymous openbaar model (no premature IN_BEHANDELING/personal-data plumbing — deferred in ADR-0008).
Behavior: /behandel/werkbak is 401 without a token, 403 for a medewerker lacking the role, 200 + werkbak for a behandelaar.
S-12c-2 (next): POST /behandel/registrations/{id}/decide → domain decision + complete the Flowable task.
Definition of Done
Linked issue: #13 (umbrella, refs); closes the adr-proposal #84
Tests first; red → green per layer
Unit + acceptance green (make unit): domain 78, bff 23, acceptance 9 (+ acl/event-subscriber unaffected)
api-client test green; openapi.json regenerated (drift guard passes)
Mutation ≥ break(90): domain 100%, bff 100%
ADR-0013 added; Keycloak__MedewerkerAuthority wired into compose
## What & why
First half of **S-12c** (behandel-portal backend), per **ADR-0013** (decisions recorded in #84):
- **BFF multi-realm auth.** A second JWT bearer scheme (`medewerker`) alongside the default `digid` scheme. On validation it lifts Keycloak's `realm_access.roles` onto the principal, and a `behandelaar` policy (medewerker scheme + `behandelaar` role) gates `/behandel/*`. Self-service keeps the digid scheme.
- **Werkbak = Flowable tasks.** The domain `Werkbak` query reads the open `Beoordelen` tasks (§8.2, S-12b's `IUserTaskClient`) and enriches each with its aggregate's bsn + status; `GET /behandel/werkbak` (domain) is proxied by the BFF `GET /behandel/werkbak` behind the behandelaar policy. The read projection stays the anonymous openbaar model (no premature `IN_BEHANDELING`/personal-data plumbing — deferred in ADR-0008).
Behavior: `/behandel/werkbak` is **401** without a token, **403** for a medewerker lacking the role, **200 + werkbak** for a behandelaar.
**S-12c-2** (next): `POST /behandel/registrations/{id}/decide` → domain decision + complete the Flowable task.
## Definition of Done
- [x] Linked issue: #13 (umbrella, `refs`); closes the adr-proposal #84
- [x] Tests first; red → green per layer
- [x] Unit + acceptance green (`make unit`): domain 78, bff 23, acceptance 9 (+ acl/event-subscriber unaffected)
- [x] api-client `test` green; openapi.json regenerated (drift guard passes)
- [x] Mutation ≥ break(90): **domain 100%, bff 100%**
- [x] ADR-0013 added; `Keycloak__MedewerkerAuthority` wired into compose
- [x] CI green (pending)
Part of #13. closes #84
The Werkbak use-case reads the open Beoordelen tasks (§8.2) and enriches each with
its aggregate's bsn + status; exposed as GET /behandel/werkbak for the BFF to proxy.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Red — the medewerker JWT scheme, the behandelaar policy, and the werkbak endpoint
do not exist yet (endpoint 404s).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a second JWT bearer scheme for the medewerker realm; on validation it lifts
Keycloak's realm_access.roles onto the principal so the behandelaar policy can
require the role. /behandel/werkbak proxies the domain werkbak behind that policy
(401 without a token, 403 without the role). openapi.json + api-client regenerated;
Keycloak__MedewerkerAuthority wired into compose.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The medewerker scheme intermittently hung ~2s fetching OIDC metadata from its
(unreachable) test authority and then 401'd — clearing Authority alone left
JwtBearer's PostConfigure free to build a ConfigurationManager under CI timing. Give
both test schemes a StaticConfigurationManager so metadata is never fetched, making
token validation deterministic. Also harden AddRealmRoles to never throw (a throw in
OnTokenValidated surfaces as a 401) — a malformed realm_access yields no roles (403).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
not
merged commit 9c3da48d8e into main2026-07-15 09:54:03 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What & why
First half of S-12c (behandel-portal backend), per ADR-0013 (decisions recorded in #84):
medewerker) alongside the defaultdigidscheme. On validation it lifts Keycloak'srealm_access.rolesonto the principal, and abehandelaarpolicy (medewerker scheme +behandelaarrole) gates/behandel/*. Self-service keeps the digid scheme.Werkbakquery reads the openBeoordelentasks (§8.2, S-12b'sIUserTaskClient) and enriches each with its aggregate's bsn + status;GET /behandel/werkbak(domain) is proxied by the BFFGET /behandel/werkbakbehind the behandelaar policy. The read projection stays the anonymous openbaar model (no prematureIN_BEHANDELING/personal-data plumbing — deferred in ADR-0008).Behavior:
/behandel/werkbakis 401 without a token, 403 for a medewerker lacking the role, 200 + werkbak for a behandelaar.S-12c-2 (next):
POST /behandel/registrations/{id}/decide→ domain decision + complete the Flowable task.Definition of Done
refs); closes the adr-proposal #84make unit): domain 78, bff 23, acceptance 9 (+ acl/event-subscriber unaffected)testgreen; openapi.json regenerated (drift guard passes)Keycloak__MedewerkerAuthoritywired into composePart of #13. closes #84