9.5 KiB
title, source_type, url, archive_url, related_branches, related_projects, tags, created, last_reviewed
| title | source_type | url | archive_url | related_branches | related_projects | tags | created | last_reviewed | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Keycloak Authorization Services — Realm vs Client Roles, Permission Model, JWT Claims | official-doc | https://www.keycloak.org/docs/latest/authorization_services/index.html |
|
|
|
2026-06-08 | 2026-06-08 |
Keycloak Authorization Services — Realm vs Client Roles, Permission Model, JWT Claims
Layer:
raw/official-docs/— Keycloak 공식 Authorization Services 문서 + JWT claim 구조 (realm_access / resource_access). feature-authentication-authorization-contract 의 IdP side permission model 결정의 근거.
Parent / 활용 branch (필수)
| Branch | 이 자료가 정당화하는 결정 |
|---|---|
| raw/branch-notes/feature-authentication-authorization-contract | Keycloak realm/client roles 을 JWT 로 전달받아 Spring Security ROLE_* authority 로 매핑하고, application-level permission check 는 별도 port 로 처리하는 설계 결정 근거 |
출처 / Source
Keycloak Authorization Services:
- 원본 URL: https://www.keycloak.org/docs/latest/authorization_services/index.html
- 저자 / 조직: Keycloak (Red Hat / CNCF)
- 발행일: rolling docs (Keycloak 25+)
- 마지막 확인일: 2026-06-08
JWT claim mapping (community technical article, betweendata.io):
- URL: https://betweendata.io/posts/secure-spring-rest-api-using-keycloak/
- 주의: official-doc 이 아닌 engineering article — claims 에
source_type별도 표시
왜 저장했는지 / Why archived
Keycloak 이 JWT 에 realm_access.roles 와 resource_access[client].roles 두 가지 형태로 role 을 전달하고, Spring Security 는 이를 기본 지원하지 않아 custom JwtGrantedAuthoritiesConverter 가 필요함. 또한 Keycloak Authorization Services 의 fine-grained permission model 이 존재하지만, application-level authorization 과의 책임 분리를 결정하는 근거로 필요.
핵심 인용 / Key quotes (verbatim)
Keycloak Authorization Services
[§Authorization services overview] "A permission associates the object being protected with the policies that must be evaluated to determine whether access is granted."
[§Permission model — expression] "X CAN DO Y ON RESOURCE Z" — where X represents users/roles/groups, Y represents actions, Z represents protected resources.
[§Terminology — Resource] "A resource is part of the assets of an application and the organization. It can be a set of one or more endpoints, a classic web resource such as an HTML page, and so on."
[§Terminology — Scope] "A resource's scope is a bounded extent of access that is possible to perform on a resource...scope can also be related to specific information provided by a resource."
[§Fine-grained capabilities] "Policies are strongly related to the different access control mechanisms (ACMs) that you can use to protect your resources. With policies, you can implement strategies for attribute-based access control (ABAC), role-based access control (RBAC), context-based access control, or any combination of these."
Keycloak JWT Claim Structure (from community technical article)
[betweendata.io — JWT structure] "In the access token, realm roles appear under the realm_access claim containing a roles array" and "Resource roles are nested under resource_access, organized by client name, with each resource potentially containing its own roles collection."
{
"realm_access": {
"roles": ["admin", "user"]
},
"resource_access": {
"my-app": {
"roles": ["app-user"]
}
}
}
[betweendata.io — Spring Security gap] "Keycloak stores roles in custom claims like realm_access and resource_access, while Spring Security expects them in claims like roles or authorities."
[betweendata.io — custom converter] "implements a custom converter that extracts the roles from where they are by default," using a Converter<Jwt, Collection> that parses both claim levels.
[betweendata.io — prefix convention] Realm roles: "ROLE_realm_" prefix. Client roles: "ROLE_[CLIENT_NAME]_" prefix.
Spring Security Resource Server JWT (official)
[Spring Security JWT docs] "A JWT that is issued from an OAuth 2.0 Authorization Server will typically either have a scope or scp attribute, indicating the scopes (or authorities) it's been granted. When this is the case, Resource Server will attempt to coerce these scopes into a list of granted authorities, prefixing each scope with the string 'SCOPE_'."
[Spring Security JWT docs — custom claim] "As part of configuring a JwtAuthenticationConverter, you can supply a subsidiary converter to go from Jwt to a Collection of granted authorities." (via setAuthoritiesClaimName / setAuthorityPrefix)
Claims Extracted / 추출된 주장
| Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove |
|---|---|---|---|---|---|
| KC-AUTHZ-C1 | Keycloak Authorization Services 는 X CAN DO Y ON RESOURCE Z 로 표현되는 permission model 을 제공하며, ABAC / RBAC / context-based 를 모두 지원 |
[§permission expression] "X CAN DO Y ON RESOURCE Z" + [§fine-grained] "implement strategies for attribute-based access control (ABAC), role-based access control (RBAC)..." | official-vendor-doc |
Keycloak 의 IdP-side fine-grained authorization 이 필요한 경우 | application-level authorization 을 Keycloak 에 완전 위임하는 것이 항상 바람직하다는 것은 아님 |
| KC-AUTHZ-C2 | Keycloak JWT 에서 realm roles 은 realm_access.roles, client roles 은 resource_access[clientId].roles claim 에 위치 — Spring Security 기본 매핑과 불일치 |
[betweendata.io] "realm roles appear under the realm_access claim" + "Resource roles are nested under resource_access" | engineering-blog (community article, NOT official-vendor-doc) |
Keycloak + Spring Security OAuth2 Resource Server 통합 | 모든 Keycloak 버전에서 이 claim 위치가 동일하게 유지된다는 것은 아님 — Keycloak 설정에 따라 다를 수 있음 |
| KC-AUTHZ-C3 | Spring Security 기본 JWT 파싱은 scope/scp claim 을 SCOPE_ prefix 로, role claim 은 자동 추출하지 않음 → Keycloak role 을 ROLE_* authority 로 쓰려면 custom JwtGrantedAuthoritiesConverter 필요 |
[Spring Security JWT docs] "Resource Server will attempt to coerce these scopes into a list of granted authorities, prefixing each scope with the string 'SCOPE_'" + custom converter needed | official-vendor-doc |
Keycloak realm/client role → Spring ROLE_* authority 매핑 설계 |
이 매핑이 application-level permission check 의 완전한 대체가 된다는 것은 아님 |
| KC-AUTHZ-C4 | Keycloak Authorization Services (fine-grained) 는 resource + scope 기반으로 IdP 에서 permission 결정을 내리지만, application-level authorization logic 과의 책임 경계 분리 에 대한 공식 권고는 문서에 없음 | [§Terminology — Scope] "A resource's scope is a bounded extent of access that is possible to perform on a resource" | official-vendor-doc |
Keycloak Authorization Services 를 application authorization 대리로 쓰는 아키텍처 평가 | 이것이 실제 production 에서 권장/비권장인지 — 문서는 capabilities 만 기술 |
Usage Boundaries / 적용 경계
- 이 자료가 직접 증명하는 것:
KC-AUTHZ-C1: Keycloak Authorization Services 는 ABAC/RBAC/context-based 지원KC-AUTHZ-C2: JWT claim 위치 (realm_access.roles/resource_access[client].roles) — 단 community article 수준KC-AUTHZ-C3: Spring Security 기본은scope→SCOPE_*, Keycloak role 자동 추출 없음 (official)
- 이 자료가 증명하지 않는 것:
- Keycloak Authorization Services 를 쓰지 말아야 한다는 것
- application-level
AuthorizationPort가 Keycloak Authorization Services 보다 낫다는 것 KC-AUTHZ-C2는 community article 기반 — official Keycloak token 구조 문서로 확인 필요
- 내 프로젝트에 적용하려면 추가 확인이 필요한 것:
- ca-skeleton 에서 사용하는 Keycloak 버전의 realm_access / resource_access claim 위치가 변경되지 않았는지
- application-level permission 만으로 충분한지 vs Keycloak Authorization Services UMA flow 까지 도입할지의 복잡도 trade-off
메모 / Notes
- Keycloak Authorization Services vs. application-level: Keycloak Authorization Services 는 강력하지만 복잡함 (UMA 2.0, policy evaluation endpoint, resource server registration). 단순 permission check 에는 application-level
AuthorizationPort가 훨씬 간단하고 테스트하기 쉬움 - realm roles vs client roles: realm roles = organization-wide (예:
ADMIN,USER). client roles = app-specific (예:portfolio:write). 이 프로젝트에서ROLE_*authority 로 매핑하는 것은 realm roles 대상이 일반적 - 주의:
KC-AUTHZ-C2는 engineering blog (betweendata.io) 기반 — official Keycloak 문서 (https://www.keycloak.org/docs/latest/server_admin/index.html#assigning-permissions-using-roles-and-groups) 로 별도 확인 권장
Related / 관련
- raw/official-docs/spring-security-resource-server-jwt — JWT authority mapping 상세
- raw/official-docs/spring-security-authorization-architecture — enforcement mechanism
- raw/branch-notes/feature-authentication-authorization-contract