Story 1.4: Keycloak Role Mapping & Application Authorization
Status: done
Story
As a a developer,
I want Keycloak roles mapped to application permission policies enforced on API routes and frontend features,
so that each user sees only the capabilities appropriate to their operational role.
Acceptance Criteria
- Given a Keycloak user has the ClientServices role When they authenticate and navigate Then they can access municipality profile and election-cycle creation routes and cannot access admin-only or production-only routes
- Given a Keycloak user has the Admin role When they authenticate Then they can access all application routes including admin-sensitive functions
- Given a user without a recognized application role authenticates When they access any protected route Then they receive 403 Forbidden and the unauthorized access attempt is logged with actor identity
- Given a privileged operation is performed When it completes Then the authorization check result, actor, and resource are captured by the audit logging service within 5 seconds (NFR6, NFR7) And roles ClientServices, Production, Transportation, Support, and Admin are managed entirely in Keycloak Admin Console — FR27 is satisfied without a custom role management UI
Tasks / Subtasks
Review Findings
Dev Notes
- Follow Epic 1 architecture constraints: ASP.NET Core + React separation, RBAC-aware patterns, and immutable legacy tables.
- Reuse shared component and workflow patterns defined in UX and architecture docs; avoid parallel custom implementations.
- Keep changes scoped to this story; do not pull forward Epic 2+ features.
Project Structure Notes
- Backend:
Campaign_Tracker.Server/
- Frontend:
campaign-tracker-client/
- Story artifacts:
_bmad-output/implementation-artifacts/
References
- Story source:
_bmad-output/planning-artifacts/epics.md (Epic 1 / Story 1.4)
- Architecture constraints:
_bmad-output/planning-artifacts/architecture.md
- UX patterns:
_bmad-output/planning-artifacts/ux-design-specification.md
Dev Agent Record
Agent Model Used
GPT-5 Codex
Debug Log References
- Story generated from epic source and architecture/UX planning artifacts.
- 2026-05-05:
dotnet test .\Campaign_Tracker.Server.Tests\Campaign_Tracker.Server.Tests.csproj /p:UseAppHost=false passed (11 tests).
- 2026-05-05:
npm test passed (2 files, 15 tests).
- 2026-05-05:
npm run lint passed.
- 2026-05-05:
dotnet build .\campaign-tracker.sln /p:UseAppHost=false passed with 0 warnings and 0 errors.
- 2026-05-05:
npm run build passed; Vite reported the existing Ant Design large chunk warning.
Completion Notes List
- Story context created and marked ready-for-dev.
- Implemented normalized Keycloak role mapping for ClientServices, Production, Transportation, Support, and Admin, including legacy aliases from the previous auth story and nested Keycloak
realm_access / resource_access role claims.
- Added backend authorization policies for ClientServices, Production, Admin, and recognized application-role access; Admin is treated as the all-access role.
- Added protected route probes for municipality profile, election-cycle creation, production queue, admin settings, and privileged admin operation to enforce and test policy behavior.
- Added authorization audit capture for denied route access and allowed privileged operations, recording actor identity, authorization result, resource, and trace identifier.
- Added frontend permission mapping and role-gated workspace navigation/actions so users only see features allowed by their Keycloak roles.
- No custom role-management UI was added; roles remain managed entirely in Keycloak Admin Console, and no legacy Access write path was introduced.
- Applied code-review fixes for unrecognized-role blocking, frontend
resource_access role parsing, deterministic multi-role workspace priority, and malformed Keycloak role-claim handling.
- Deferred production-surface treatment of
AuthorizationProbeController by user choice; tracked in _bmad-output/implementation-artifacts/deferred-work.md.
File List
Campaign_Tracker.Server.Tests/ApplicationAuthorizationTests.cs
Campaign_Tracker.Server.Tests/AuthEndpointTests.cs
Campaign_Tracker.Server/Authentication/AuthenticationAuditEvent.cs
Campaign_Tracker.Server/Authentication/IAuthenticationAuditStore.cs
Campaign_Tracker.Server/Authentication/InMemoryAuthenticationAuditStore.cs
Campaign_Tracker.Server/Authentication/RoleWorkspaceResolver.cs
Campaign_Tracker.Server/Authorization/ApplicationPolicy.cs
Campaign_Tracker.Server/Authorization/ApplicationRole.cs
Campaign_Tracker.Server/Authorization/AuthorizationAuditResultHandler.cs
Campaign_Tracker.Server/Controllers/AuthSessionController.cs
Campaign_Tracker.Server/Controllers/AuthorizationProbeController.cs
Campaign_Tracker.Server/Program.cs
_bmad-output/implementation-artifacts/1-4-keycloak-role-mapping-application-authorization.md
_bmad-output/implementation-artifacts/sprint-status.yaml
campaign-tracker-client/src/auth/authContracts.test.ts
campaign-tracker-client/src/auth/authContracts.ts
campaign-tracker-client/src/workspace/WorkspaceShell.tsx
Change Log
| Date |
Version |
Description |
Author |
| 2026-05-05 |
1.0 |
Implemented Keycloak role mapping, backend authorization policies, audit evidence for denied/privileged authorization checks, frontend permission gates, and validation tests. |
GPT-5 Codex |
| 2026-05-06 |
1.1 |
Applied code-review fixes, recorded deferred probe-controller follow-up, and marked story done. |
GPT-5 Codex |