14 KiB
title, source_type, url, archive_url, related_projects, related_branches, tags, status, confidence, created, last_reviewed
| title | source_type | url | archive_url | related_projects | related_branches | tags | status | confidence | created | last_reviewed | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Spring Security — OAuth 2.0 Resource Server JWT (issuer-uri, JwtDecoder) | official-doc | https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/jwt.html |
|
|
|
raw | high | 2026-05-25 | 2026-05-27 |
Spring Security — OAuth 2.0 Resource Server JWT (issuer-uri, JwtDecoder)
Layer:
raw/official-docs/— Spring Security Reference / "OAuth 2.0 Resource Server / JWT" 페이지 verbatim. P2A/P3A 의 Spring Boot Resource Server (/api/me등) 가 Keycloak JWT 를 검증하는 최소 설정 + audience/role 매핑 customize 의 1차 근거.
Parent / 활용 branch (필수)
| Branch | 이 자료가 정당화하는 결정 |
|---|---|
| raw/branch-notes/feature-keycloak-patterns | keycloak-patterns root — Resource Server 가 issuer-uri 한 줄로 OIDC discovery → JWKS 검증을 자동 구성한다는 사실 |
| raw/branch-notes/feature-keycloak-single-ec2-no-google | P3A 단일 EC2 학습 환경 backend (application.yml) 의 spring.security.oauth2.resourceserver.jwt.issuer-uri 설정 근거 |
| raw/branch-notes/feature-keycloak-spring-rs-audience-validator | audiences property 로 aud claim 검증 추가 결정 근거 (token 이 의도된 RS 로 발급되었는지) |
| raw/branch-notes/feature-keycloak-spring-rs-role-mapping | Keycloak realm role → Spring GrantedAuthority 매핑 시 JwtAuthenticationConverter + SCOPE_ prefix 의 default 동작 근거 |
| raw/branch-notes/feature-keycloak-iss-claim-hostname-mismatch | issuer-uri 와 token iss 가 정확 일치해야 한다는 startup expectation 의 근거 (Keycloak KC_HOSTNAME 함정) |
컨텍스트
P2A/P3A 의 backend (/api/me) 는 Spring Boot 3.x + spring-security-oauth2-resource-server 로 구현. issuer-uri 한 줄로 OIDC discovery + JWKS 자동 fetch + iss 검증이 동작한다는 점이 Keycloak 통합의 최소 구성 단위. audience 검증 + 권한 추출 customize 는 keycloak realm role 매핑의 1차 근거.
출처 / Source
- 원본 URL: https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/jwt.html
- 아카이브 URL: (미수집)
- 저자 / 조직: Spring Security (VMware / Broadcom)
- 발행일: rolling docs (current = 6.x)
- 마지막 확인일: 2026-05-27
핵심 인용 / Key quotes (verbatim)
[§Specifying the Authorization Server] "Where
idp.example.com/issueris the value contained in theissclaim for JWT tokens that the authorization server will issue. Resource Server will use this property to further self-configure, discover the authorization server's public keys, and subsequently validate incoming JWTs."
[§Startup Expectations] "It achieves this through a deterministic discovery process it launches at the first request containing a JWT: 1. Query the Provider Configuration or Authorization Server Metadata endpoint for the
jwks_urlproperty 2. Query thejwks_urlendpoint for supported algorithms 3. Configure the validation strategy to queryjwks_urlfor valid public keys of the algorithms found 4. Configure the validation strategy to validate each JWTsissclaim againstidp.example.com."
[§How JWT Authentication Works] "
JwtAuthenticationProvideris anAuthenticationProviderimplementation that leverages aJwtDecoderandJwtAuthenticationConverterto authenticate a JWT."
[§Configuring Authorization] "A JWT that is issued from an OAuth 2.0 Authorization Server will typically either have a
scopeorscpattribute, indicating the scopes (or authorities) it's been granted, for example:{ …, \"scope\" : \"messages contacts\"}"
[§Configuring Authorization] "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_"."
[§Specifying the Authorization Server JWK Set Uri Directly] "If the authorization server doesn't support any configuration endpoints, or if Resource Server must be able to initialize independently from the authorization server, then the
jwk-set-urican be supplied as well"
[§Specifying the Authorization Server JWK Set Uri Directly] "Consequently, Resource Server will not ping the authorization server at startup. We still specify the
issuer-uriso that Resource Server still validates theissclaim on incoming JWTs."
[§Supplying Audiences] "Boot also has the
audiencesproperty for validating theaudclaim; this is who the JWT was sent to."
[§Supplying Audiences] "The result will be that if the JWT's
issclaim is notidp.example.com, and itsaudclaim does not containmy-resource-server.example.comin its list, then validation will fail."
Claims Extracted / 추출된 주장
| Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove |
|---|---|---|---|---|---|
| SSRS-JWT-C1 | issuer-uri property 는 token iss 값이어야 하며, Resource Server 는 이 값으로 self-configure (authorization server public key discovery + JWT 검증) |
[§Specifying the Authorization Server] "Where idp.example.com/issuer is the value contained in the iss claim for JWT tokens that the authorization server will issue. Resource Server will use this property to further self-configure, discover the authorization server's public keys, and subsequently validate incoming JWTs." |
official-vendor-doc |
Spring Security 6.x + OAuth2 Resource Server (servlet) | issuer-uri 가 Keycloak 의 KC_HOSTNAME 과 어떻게 매핑되는지의 정확한 형태는 본 인용 범위 밖 (Keycloak 별도 문서) |
| SSRS-JWT-C2 | startup 시 첫 JWT 요청에서 deterministic discovery 4단계 수행: (1) jwks_url 조회 (2) supported algorithms 확인 (3) JWKS 로 public key 검증 strategy 구성 (4) iss claim 을 issuer-uri 와 비교 |
[§Startup Expectations] "It achieves this through a deterministic discovery process it launches at the first request containing a JWT: 1. Query the Provider Configuration or Authorization Server Metadata endpoint for the jwks_url property 2. Query the jwks_url endpoint for supported algorithms 3. Configure the validation strategy to query jwks_url for valid public keys of the algorithms found 4. Configure the validation strategy to validate each JWTs iss claim against idp.example.com." |
official-vendor-doc |
Boot auto-configuration 사용 시 | discovery 실패 시 retry/backoff 정책은 본 인용 범위 밖 |
| SSRS-JWT-C3 | JwtAuthenticationProvider 는 JwtDecoder + JwtAuthenticationConverter 를 사용해 JWT 를 인증하는 AuthenticationProvider 구현체 |
[§How JWT Authentication Works] "JwtAuthenticationProvider is an AuthenticationProvider implementation that leverages a JwtDecoder and JwtAuthenticationConverter to authenticate a JWT." |
official-vendor-doc |
Spring Security JWT authentication chain | reactive (WebFlux) 변형의 클래스명은 본 인용 범위 밖 |
| SSRS-JWT-C4 | JWT 의 scope/scp claim 의 각 scope 는 default 로 SCOPE_ prefix 가 붙은 granted authority 로 변환 |
[§Configuring Authorization] "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_"." | official-vendor-doc |
default JwtAuthenticationConverter 사용 시 |
Keycloak realm role (realm_access.roles) 이 default 로 자동 매핑된다는 뜻은 아님 — Keycloak role 매핑은 JwtGrantedAuthoritiesConverter 의 setAuthoritiesClaimName customize 필요 |
| SSRS-JWT-C5 | jwk-set-uri 를 직접 지정 가능; 이 경우 startup 시 authorization server ping 안 함. 단 issuer-uri 는 여전히 명시 (token iss 검증을 위해) |
[§Specifying the Authorization Server JWK Set Uri Directly] "If the authorization server doesn't support any configuration endpoints, or if Resource Server must be able to initialize independently from the authorization server, then the jwk-set-uri can be supplied as well" + "Consequently, Resource Server will not ping the authorization server at startup. We still specify the issuer-uri so that Resource Server still validates the iss claim on incoming JWTs." |
official-vendor-doc |
authorization server 가 OIDC discovery 미지원 또는 RS 가 독립 부팅 요구 | jwk-set-uri 단독 (issuer 없음) 사용 시 동작은 본 인용 범위 밖 |
| SSRS-JWT-C6 | Boot 의 audiences property 는 aud claim 검증을 활성화; iss 또는 aud 어느 하나라도 불일치 시 검증 실패 |
[§Supplying Audiences] "Boot also has the audiences property for validating the aud claim; this is who the JWT was sent to." + "The result will be that if the JWT's iss claim is not idp.example.com, and its aud claim does not contain my-resource-server.example.com in its list, then validation will fail." |
official-vendor-doc |
Boot auto-configuration + audiences property 사용 |
programmatic aud validator (별도 OAuth2TokenValidator) 의 정확한 추가 방식은 본 인용 범위 밖 — 별도 §Configuring Validation 페이지 참조 |
Usage Boundaries / 적용 경계
- 이 자료가 직접 증명하는 것:
SSRS-JWT-C1:issuer-uri한 줄로 OIDC discovery + JWKS +iss검증이 자동화된다는 사실SSRS-JWT-C2: 4단계 deterministic discovery 의 정확한 순서SSRS-JWT-C3:JwtAuthenticationProvider의 두 협력자 (JwtDecoder,JwtAuthenticationConverter) 의 정확한 명명SSRS-JWT-C4:scope/scpclaim →SCOPE_prefix 자동 변환의 default 동작SSRS-JWT-C5:jwk-set-uri직접 지정 +issuer-uri병기 패턴SSRS-JWT-C6:audiencesproperty 의aud검증 활성화 + 실패 조건
- 이 자료가 증명하지 않는 것:
- Keycloak
realm_access.rolesclaim 이 default 로ROLE_prefix 의 granted authority 로 매핑된다는 뜻 — Keycloak realm role 은scope/scp가 아닌 별도 nested claim 이므로JwtAuthenticationConvertercustomize 필수 - opaque token introspection (별도
/oauth2/introspection페이지) issuer-uri가 Keycloak 의KC_HOSTNAME변경 시 자동 추적된다는 뜻 — startup 시점에 한 번만 discovery- WebFlux/reactive 환경의 클래스명 (
ReactiveJwtDecoder등) 의 정확한 매핑
- Keycloak
- 내 프로젝트에 적용하려면 추가 확인이 필요한 것:
- P3A 의
KC_HOSTNAME=localhost와 backendissuer-uri=http://localhost:8080/realms/keycloak-patterns일치 검증 (token 의iss가 정확히 동일한지 token 디코딩 확인) - Keycloak realm role 을
ROLE_prefix 의 authority 로 매핑하는JwtGrantedAuthoritiesConverter의 정확한setAuthoritiesClaimName값 (realm_access.rolesvsresource_access.<client>.roles) audiencesproperty 가 string list 인지 single string 인지 (Boot 3.x property binding 형식)
- P3A 의
최소 설정 (해석 — 내 프로젝트 메모)
본 섹션은 자료 직접 인용 아님. P3A 적용 가이드.
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://localhost:8080/realms/keycloak-patterns
- 첫 요청 시 위
SSRS-JWT-C2의 4단계 deterministic discovery 자동 수행.
JWKS URI 직접 지정 (해석)
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://localhost:8080/realms/keycloak-patterns
jwk-set-uri: http://localhost:8080/realms/keycloak-patterns/protocol/openid-connect/certs
Audience 검증 (해석)
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://localhost:8080/realms/keycloak-patterns
audiences: keycloak-patterns-backend
권한 추출 customize (해석)
@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter conv = new JwtGrantedAuthoritiesConverter();
conv.setAuthoritiesClaimName("realm_access.roles"); // Keycloak realm role
conv.setAuthorityPrefix("ROLE_");
JwtAuthenticationConverter jac = new JwtAuthenticationConverter();
jac.setJwtGrantedAuthoritiesConverter(conv);
return jac;
}
P3A 적용 메모 (내 프로젝트 해석)
본 섹션은 자료 직접 인용 아님. P3A 결정 컨텍스트 해석.
issuer-uri는 Keycloak 이 발급한 token 의iss와 정확히 동일해야 함 (SSRS-JWT-C1+C2.4) → KeycloakKC_HOSTNAME=localhost라면 backend 도http://localhost:8080/realms/..../api/me등 endpoint 는.oauth2ResourceServer(o -> o.jwt(Customizer.withDefaults()))한 줄로 보호.@AuthenticationPrincipal Jwt jwt로 컨트롤러에서 claim 접근 →jwt.getClaimAsString("preferred_username").
한계 / 후속
- 본 문서는 JWT validation 만. opaque token introspection 은 별도 페이지.
- 본 wiki 변환 시
wiki/concepts/spring-security-resource-server-jwt후보.
Related / 관련
- 같은 주제 다른 official-doc:
- 인용하는 branch:
- 인용하는 wiki: (미작성)