Per ADR-0025's implementation phasing, lands the closed-set
catalogues + the OIDC-callback hook that composes the
session-resident Principal. No new guards yet.
- libs/shared/auth: framework-agnostic lib hosting
authorization.types.ts (4 privileges + 24 functional roles + 6
scope kinds + Principal type) and entra-group-to-role.ts
(validated GUID -> slug resolver). 17 unit tests against the
catalogues + resolver contracts.
- BFF: PrincipalBuilder composes the three axes once at sign-in;
ScopeResolver seam (StubScopeResolver returns unrestricted in
v1, replaced by a Prisma-backed implementation when ADR-0026's
user_scopes table lands). 19 persona-driven tests covering the
test tenant's full provisioning + edge cases (unknown
privilege drift, unknown group GUID, empty permissions).
- AuthService extracts the Entra "groups" claim; AuthenticatedUser
grows the groups: readonly string[] field.
- SessionEstablisher builds + persists the principal alongside
the legacy user shape (additive — guards consuming user.oid
unchanged).
- ENTRA_GROUP_MAP_PATH env var + load-entra-group-map.ts read
the tenant-private map from infra/<env>-tenant.entra.json
(gitignored; .example.json committed with the schema).
- ADR-0025 path references updated from libs/feature/auth
(Angular-scoped, scope:portal-shell) to libs/shared/auth
(consumable by both BFF and SPA).
- notes/entra-groups-claim-activation.md: operator runbook for
the "Token configuration -> Add groups claim" step in the
Entra admin centre.
Test plan:
- pnpm nx affected -t lint test build : 13 projects green
(497 BFF tests + 17 shared-auth tests + 1 shared-util test +
full lint + full build).