Skip to content

feat(ledger): enforce per-endpoint keycloak scope authorization - #138

Merged
tiana-code merged 2 commits into
mainfrom
feat/E-01-scope-authorization
Jun 15, 2026
Merged

feat(ledger): enforce per-endpoint keycloak scope authorization#138
tiana-code merged 2 commits into
mainfrom
feat/E-01-scope-authorization

Conversation

@tiana-code

Copy link
Copy Markdown
Owner

What

Adds per-endpoint scope authorization to the ledger resource server:

  • maps the JWT scope claim to SCOPE_-prefixed authorities via JwtAuthenticationConverter
  • GET /v1/** requires SCOPE_ledger:read; mutating /v1/** (POST/PUT/PATCH/DELETE) requires SCOPE_ledger:write
  • PUBLIC_PATHS (api-docs, swagger, actuator/health) stay anonymous; everything else falls to the authenticated backstop
  • configures spring.security.oauth2.resourceserver.jwt.issuer-uri (required env KEYCLOAK_ISSUER_URI) so the prod context boots (closes the Configure Spring Security resource server (Keycloak JWT) #47 residual)

A valid token with the wrong scope now returns 403, which activates the previously dormant DENIED audit path from #133 with no audit-code change.

Scope taxonomy

Method Path Authority
POST /v1/accounts SCOPE_ledger:write
GET /v1/accounts, /{id}, /{id}/balance, /{id}/entries SCOPE_ledger:read
POST /v1/transactions, /{id}/reverse SCOPE_ledger:write
GET /v1/transactions, /{id} SCOPE_ledger:read

Tests

  • new ScopeAuthorizationMatrixIT: full 9-endpoint matrix, allowed-with-correct-scope vs 403-with-opposite-scope, side-effect-light on the shared container
  • @WebMvcTest cross-scope 403 guards in both controller tests
  • existing ITs updated to carry the scopes their calls require (no behavioral regression)
  • DeniedAuditIT simplified to assert the real 403 rule instead of a test-only denyAll chain
  • anonymous /actuator/health coverage added

401 (unauthenticated, no audit) vs 403 (authenticated wrong scope, DENIED audit) split preserved.

Closes #47
Closes #48

@tanya_r added 2 commits June 15, 2026 20:26
map the jwt scope claim to authorities and require ledger:read on read
endpoints and ledger:write on mutating /v1 endpoints. a valid token with
the wrong scope now returns 403, which activates the dormant denied audit
path. configure the resource server issuer-uri and update the existing
tests to carry the required scopes.

Closes #47
Closes #48
the scope matrix it used the scope string as the bearer token value, but a
colon is not a valid bearer token character so the resolver rejected it and
every request returned 401. use colon-free token values and build the scope
claim in the decoder. also raise the shared test postgres max_connections so
the added springboottest context does not exhaust the connection ceiling.
@tiana-code
tiana-code merged commit ff8c1fa into main Jun 15, 2026
6 checks passed
@tiana-code
tiana-code deleted the feat/E-01-scope-authorization branch June 15, 2026 23:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Per-endpoint Keycloak scope authorization (ledger:read / ledger:write) Configure Spring Security resource server (Keycloak JWT)

1 participant