# 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 1. **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 2. **Given** a Keycloak user has the Admin role **When** they authenticate **Then** they can access all application routes including admin-sensitive functions 3. **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 4. **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 - [x] Implement story behavior in aligned backend/frontend modules (AC: #1) - [x] Add or update API/service/UI components required by the story scope - [x] Keep legacy Access entities read-only and route writes to extension-layer structures - [x] Cover acceptance criteria #2 in implementation and tests (AC: #2) - [x] Add validation/error handling and UX state updates as needed - [x] Cover acceptance criteria #3 in implementation and tests (AC: #3) - [x] Add validation/error handling and UX state updates as needed - [x] Cover acceptance criteria #4 in implementation and tests (AC: #4) - [x] Add validation/error handling and UX state updates as needed - [x] Validate and document completion evidence - [x] Verify build/tests for touched modules - [x] Capture changed files and any migration/config implications ### Review Findings - [x] [Review][Defer] AuthorizationProbeController ships canned operational routes in the production controller surface [Campaign_Tracker.Server/Controllers/AuthorizationProbeController.cs:8] — deferred by user choice during review. - [x] [Review][Patch] Unrecognized roles can still render the workspace shell instead of a forbidden state [campaign-tracker-client/src/App.tsx:25] - [x] [Review][Patch] Frontend role mapping ignores Keycloak resource_access client roles [campaign-tracker-client/src/auth/authContracts.ts:322] - [x] [Review][Patch] Multi-role workspace selection is order-dependent on the server and can diverge from frontend priority [Campaign_Tracker.Server/Authentication/RoleWorkspaceResolver.cs:17] - [x] [Review][Patch] Malformed realm_access/resource_access JSON can throw during token validation [Campaign_Tracker.Server/Authorization/ApplicationRole.cs:78] ## 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 |