12 KiB
title, source_type, url, archive_url, related_branches, related_projects, tags, status, confidence, created, last_reviewed
| title | source_type | url | archive_url | related_branches | related_projects | tags | status | confidence | created | last_reviewed | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Nimbus JOSE+JWT — JWKSourceBuilder (rate-limit, refresh-ahead cache, unknown-kid) + Spring Security NimbusJwtDecoder JWKS integration | official-doc | https://connect2id.com/products/nimbus-jose-jwt/examples/enhanced-jwk-retrieval |
|
|
|
raw | high | 2026-06-08 | 2026-06-08 |
Nimbus JOSE+JWT — JWKSourceBuilder (rate-limit, refresh-ahead cache, unknown-kid) + Spring Security NimbusJwtDecoder JWKS integration
Layer:
raw/official-docs/— Nimbus JOSE+JWT 공식 문서 + Spring Security source 에서 확인된 JWKS 관리 API. D10 (UNSUPPORTED_DECISION) 해소를 위한 1차 vendor 근거.
Parent / 활용 branch (필수)
| Branch | 이 자료가 정당화하는 결정 |
|---|---|
| raw/branch-notes/feature-security-operational-baseline | D10: JWKS refresh interval, unknown kid on-demand refresh rate-limit, rotation overlap window 의 mechanism 근거 (exact number 는 project trade-off 로 유지) |
출처 / Source
- 원본 URL: https://connect2id.com/products/nimbus-jose-jwt/examples/enhanced-jwk-retrieval
- 보완 URL (Spring Security source): https://github.com/spring-projects/spring-security/blob/main/oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwtDecoder.java
- 보완 URL (Spring Security reference): https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/jwt.html
- 보완 URL (Spring Security issue #11621): https://github.com/spring-projects/spring-security/issues/11621
- 아카이브 URL: (미수집)
- 저자 / 조직: Connect2id (Nimbus JOSE+JWT 공식 maintainer) + Spring Security Team (VMware/Broadcom)
- 마지막 확인일: 2026-06-08
왜 저장했는지 / Why archived
Spring Security NimbusJwtDecoder 의 JWKS 캐시 기본값(5분), rate-limit 비활성화 사실, unknown kid on-demand refresh 메커니즘, refresh-ahead 캐싱 API 를 공식 vendor 레벨에서 확인하기 위해. D10 이 UNSUPPORTED_DECISION 으로 레이블된 이유는 exact number (10분, 1/min) 의 공식 근거가 없기 때문이며, 본 자료는 mechanism 의 존재 자체를 증명한다.
핵심 인용 / Key quotes (verbatim)
[Nimbus JOSE+JWT Enhanced JWK retrieval, §Overview] "The JWKSourceBuilder serves as the entry point for JWK set retrieval, wrapping sources 'with various capabilities' including rate limiting to guard against frequent network calls, with smart rate limiting designed to let through additional requests to handle potential key rotations at the source."
[Nimbus JOSE+JWT Enhanced JWK retrieval, §Rate Limiting] "The default rate limiting setting is '30 seconds between calls to the URL.'"
[Nimbus JOSE+JWT Enhanced JWK retrieval, §Refresh-Ahead Caching] "The default cache configuration provides: Cache TTL: 5 minutes. Refresh Window: '30 seconds prior to the cache's expiration the JWK set will be refreshed from the URL on a separate dedicated thread'"
[Spring Security reference, §Caching JWKS] "Also by default, Resource Server caches in-memory the authorization server's JWK set for 5 minutes, which you may want to adjust. Further, it doesn't take into account more sophisticated caching patterns like eviction or using a shared cache."
[Spring Security reference, §Caching JWKS] "When given a Cache, Resource Server will use the JWK Set Uri as the key and the JWK Set JSON as the value."
[Spring Security reference, §Key Rotation] "As the authorization server makes available new keys, Spring Security will automatically rotate the keys used to validate JWTs."
[Spring Security source NimbusJwtDecoder.java, JwkSetUriJwtDecoderBuilder.jwkSource()] "JWKSourceBuilder.create(new SpringJWKSource<>(this.restOperations, this.cache, jwkSetUri)).refreshAheadCache(false).rateLimited(false).cache(this.cache instanceof NoOpCache).build()"
[Spring Security source NimbusJwtDecoder.java, SpringJWKSource.getJWKSet()] "if (refreshEvaluator.requiresRefresh(this.jwkSet)) { this.cache.invalidate(); } this.cache.get(this.jwkSetUri, this::fetchJwks);"
[Spring Security issue #11621] "I would expect this to trigger a refresh of the JWK set, but this is not what is happening." (root cause: NimbusJwtDecoder consistently uses CachingResourceRetriever even when unknown KID is encountered). Fix: "Pull request #11638 was merged to address this issue, enabling the decoder to bypass cache and request fresh JWK Sets when an unknown KID is detected."
[Nimbus JOSE+JWT JWKSourceBuilder API, rate limiting note] "smart to let through additional requests to handle potential key rotations at the source" — rate limiting is designed to be bypassable for unknown-kid scenarios.
Claims Extracted / 추출된 주장
| Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove |
|---|---|---|---|---|---|
| NIMBUS-JWKS-C1 | Nimbus JOSE+JWT JWKSourceBuilder 의 기본 rate limit 은 두 JWKS fetch 사이 30초 간격이다 | [Nimbus docs §Rate Limiting] "The default rate limiting setting is '30 seconds between calls to the URL.'" | official-vendor-doc |
Nimbus JOSE+JWT JWKSourceBuilder 직접 사용 시 | Spring Security NimbusJwtDecoder.withJwkSetUri() 가 기본적으로 rateLimited(false) 를 사용하므로, Spring Security default path 에서 Nimbus 의 30초 rate limit 은 비활성화됨 |
| NIMBUS-JWKS-C2 | Nimbus JOSE+JWT JWKSourceBuilder 의 기본 캐시 TTL 은 5분이고, 캐시 만료 30초 전에 별도 스레드에서 refresh-ahead 를 수행한다 | [Nimbus docs §Refresh-Ahead] "Cache TTL: 5 minutes. '30 seconds prior to the cache's expiration the JWK set will be refreshed from the URL on a separate dedicated thread'" | official-vendor-doc |
Nimbus JWKSourceBuilder 직접 사용 시 | Spring Security withJwkSetUri() 가 refreshAheadCache(false) 를 사용하므로 Spring Security default path 에서 refresh-ahead 는 비활성화됨 |
| NIMBUS-JWKS-C3 | Nimbus JOSE+JWT 의 smart rate limiting 은 unknown kid 시나리오에서 추가 요청을 통과시키도록 설계되었다 | [Nimbus docs §Overview] "smart rate limiting designed to let through additional requests to handle potential key rotations at the source" | official-vendor-doc |
Nimbus JWKSourceBuilder 로 rate limit 을 활성화한 경우 | rate limit bypass 의 정확한 메커니즘 (kid match 실패 후 즉시 bypass 여부) 은 본 인용만으로 증명 불가 |
| NIMBUS-JWKS-C4 | Spring Security NimbusJwtDecoder.withJwkSetUri() 는 기본적으로 Nimbus JWKSourceBuilder 의 rate limiting 과 refresh-ahead caching 을 비활성화한다 | [Spring Security source] ".refreshAheadCache(false).rateLimited(false)" | official-vendor-doc |
Spring Boot 3.x NimbusJwtDecoder auto-configuration 또는 withJwkSetUri() 빌더 사용 시 | Spring Security 의 이 기본값이 특정 버전에서 변경될 가능성 (소스 코드 기반 확인, 버전 명시 없음) |
| NIMBUS-JWKS-C5 | Spring Security Resource Server 의 기본 JWKS 캐시 TTL 은 5분이며, Cache 인터페이스로 커스텀 캐시를 주입할 수 있다 | [Spring Security ref] "Resource Server caches in-memory the authorization server's JWK set for 5 minutes" + "When given a Cache, Resource Server will use the JWK Set Uri as the key and the JWK Set JSON as the value." | official-vendor-doc |
Spring Security 6.x Resource Server servlet stack | cache TTL 을 builder API 로 직접 설정하는 방법 (버전에 따라 Cache 구현체의 eviction 설정에 위임) |
| NIMBUS-JWKS-C6 | Spring Security NimbusJwtDecoder 는 unknown kid 감지 시 캐시를 무효화하고 JWKS 를 재조회한다 (JWKSetCacheRefreshEvaluator + cache.invalidate()) |
[Spring Security source] "if (refreshEvaluator.requiresRefresh(this.jwkSet)) { this.cache.invalidate(); }" + issue #11638 (fix for unknown KID not triggering refresh when using custom cache) | official-vendor-doc |
Spring Security 6.x (#11638 이후 버전) NimbusJwtDecoder + custom cache 사용 시 |
unknown kid 에 대한 on-demand refresh 가 rate-limited 되는지 여부 — Spring Security layer 에서는 rate limit 이 없음; 직접 구현 필요 |
| NIMBUS-JWKS-C7 | Spring Security ref 는 "As the authorization server makes available new keys, Spring Security will automatically rotate the keys used to validate JWTs" 라고 명시하지만 구체적 메커니즘(timing, kid-miss 처리) 은 명세화하지 않는다 | [Spring Security ref §Key Rotation] "As the authorization server makes available new keys, Spring Security will automatically rotate the keys used to validate JWTs." | official-vendor-doc |
Spring Security 6.x + JWKS 기반 자동 discovery 사용 시 | exact refresh timing, thundering-herd 방지, rotation overlap window duration — 모두 ref 에서 미명세 (project-level decision) |
Usage Boundaries / 적용 경계
- 이 자료가 직접 증명하는 것:
NIMBUS-JWKS-C1: Nimbus JWKSourceBuilder 의 기본 rate limit interval (30초)NIMBUS-JWKS-C2: Nimbus JWKSourceBuilder 의 기본 캐시 TTL (5분) + refresh-ahead (만료 30초 전)NIMBUS-JWKS-C3: rate limiting 이 unknown kid 시나리오에서 bypass-able 하게 설계되었다는 사실NIMBUS-JWKS-C4: Spring Security withJwkSetUri() 가 기본적으로 rateLimited(false) + refreshAheadCache(false)NIMBUS-JWKS-C5: Spring Security 기본 JWKS 캐시 TTL 5분 + Cache 인터페이스 주입 가능NIMBUS-JWKS-C6: unknown kid 시 cache.invalidate() + 재조회 메커니즘 존재 (bug fix #11638 포함)NIMBUS-JWKS-C7: Spring Security 가 자동 key rotation 을 지원한다고 명시하나 exact mechanism 은 미명세
- 이 자료가 증명하지 않는 것:
- JWKS refresh interval 을 "10분" 으로 설정해야 한다는 근거 (10분은 project trade-off —
UNSUPPORTED_DECISION유지) - unknown kid on-demand refresh rate-limit 을 "1회/1분" 으로 설정해야 한다는 근거 (1/min 은 project trade-off —
UNSUPPORTED_DECISION유지; WorkOS guide 는 "5–10분" 권고 — company-tech-blog 별도 참조) - rotation overlap window 를 "24h" 로 설정해야 한다는 근거 (24h 는 project trade-off —
UNSUPPORTED_DECISION유지)
- JWKS refresh interval 을 "10분" 으로 설정해야 한다는 근거 (10분은 project trade-off —
- 내 프로젝트에 적용하려면 추가 확인이 필요한 것:
NimbusJwtDecoder.withJwkSetUri(...).cache(caffeineCache)에서 Caffeine 의 expireAfterWrite = 10min 이 실제로 JWKS 재조회를 10분마다 트리거하는지 integration test 필요- unknown kid on-demand refresh rate limit 은 Spring Security layer 에서 기본 제공되지 않음 — 별도
JwtDecoder래퍼 또는 AOP 로 rate limit 구현 필요 - Nimbus JWKSourceBuilder 를 직접 사용 (rateLimited(true)) 하면 Spring Security의 SpringJWKSource 래퍼와 충돌 가능성 — 통합 테스트 필요
메모 / Notes
- Spring Security 의
withJwkSetUri()내부 구현이rateLimited(false)를 명시적으로 호출하므로, 10분 interval 을 구현하려면 Caffeine/EhCache 의 TTL 설정에 위임하거나,NimbusJwtDecoder.withJwkSource(JWKSourceBuilder.create(...).rateLimited(true).build())패턴으로 Nimbus builder 를 직접 사용해야 함. NIMBUS-JWKS-C6에서 unknown kid 시 rate limit 은 Spring Security 에서 제공하지 않음. thundering-herd 방지를 위한 1/min rate limit 은 application-level bucket4j/Guava RateLimiter 로 구현해야 함.- WorkOS guide ("typically 5–10 minutes" minimum refresh interval) 는
company-tech-blogsource — 별도raw/company-tech-blogs/파일 참조.
Related / 관련
- raw/official-docs/spring-security-resource-server-jwt — Spring Security Resource Server 기본 설정 (본 파일과 보완 관계)
- raw/official-docs/security-jwt-rfc-7519-validation — JWT 검증 표준 (claim validation)
- raw/branch-notes/feature-security-operational-baseline — D10 결정 컨텍스트