13 KiB
title, source_type, url, archive_url, related_branches, related_projects, tags, created
| title | source_type | url | archive_url | related_branches | related_projects | tags | created | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| official-doc / Spring Security — OAuth2 Authorized Client Features (Servlet) | official-doc | https://docs.spring.io/spring-security/reference/servlet/oauth2/client/authorized-clients.html |
|
|
2026-07-24 |
official-doc / Spring Security — OAuth2 Authorized Client Features (Servlet)
Layer:
raw/official-docs/— Spring Security 공식 레퍼런스(Servlet 스택) "Authorized Client Features" 페이지의 원문 발췌.feature-keycloak-bff-oauth2login-sessionbranch(WI-010)의 "BFF는 access/refresh token을 server-side에 보관하고, downstream Resource API 호출 시 held access token을 Bearer로 첨부한다"는 결정의 공식 벤더 근거로 보관.
Parent / 활용 branch (필수)
| Branch | 이 자료가 정당화하는 결정 |
|---|---|
| raw/branch-notes/feature-keycloak-bff-oauth2login-session | AP3(BFF) 패턴에서 (0) @RegisteredOAuth2AuthorizedClient 메서드 인자 리졸버 또는 OAuth2AuthorizedClientManager로 서버측 보유 OAuth2AuthorizedClient(token holder)를 조회(retrieve)하고, (1) OAuth2AuthorizedClient가 principal에 scope되어 server-side에 저장되며, (2) OAuth2ClientHttpRequestInterceptor(RestClient) / ServletOAuth2AuthorizedClientExchangeFilterFunction(WebClient)이 저장된 access token을 outbound resource 요청의 Bearer 헤더로 첨부하고, (3) 만료된 access token을 자동으로 refresh한다는 4가지 완료 조건 세부사항의 공식 벤더 근거 |
출처
- 원본 URL: https://docs.spring.io/spring-security/reference/servlet/oauth2/client/authorized-clients.html
- 아카이브 URL: (미수집)
- 저자 / 조직: Spring Security (VMware/Broadcom) — 공식 레퍼런스 문서
- 발행일: 고정 발행일 없음 (rolling reference doc, 버전별 URL 존재: 6.5 / 7.0 / 7.1-SNAPSHOT 등)
- 마지막 확인일: 2026-07-24
왜 저장했는지
branch feature-keycloak-bff-oauth2login-session의 완료 조건은 "browser token 0개와 SESSION cookie만으로 BFF proxy API 200이 재현된다"이다. 이를 구현하려면 Spring Security가 서버측에 보관된 OAuth2AuthorizedClient를 (a) 어떻게 조회하고, (b) 그것을 어떻게 principal에 scope하여 저장하며, (c) downstream Resource API 호출 시 보유 access token을 어떻게 꺼내 Bearer로 첨부하고, (d) 만료 시 어떻게 자동 갱신하는지에 대한 공식 근거가 필요하다. 이 페이지는 @RegisteredOAuth2AuthorizedClient/OAuth2AuthorizedClientManager(조회), PrincipalResolver(저장·스코프), OAuth2ClientHttpRequestInterceptor/ServletOAuth2AuthorizedClientExchangeFilterFunction(첨부), 자동 refresh를 모두 다루는 유일한 단일 공식 페이지다.
핵심 인용
[§Resolving an Authorized Client] "The @RegisteredOAuth2AuthorizedClient annotation is handled by OAuth2AuthorizedClientArgumentResolver, which directly uses an OAuth2AuthorizedClientManager and, therefore, inherits its capabilities."
[§RestClient Integration › Providing the principal] "OAuth2ClientHttpRequestInterceptor uses a PrincipalResolver to determine which principal name is associated with the access token, which allows an application to choose how to scope the OAuth2AuthorizedClient that is stored."
[§RestClient Integration] "This interceptor provides the ability to make protected resources requests by placing a Bearer token in the Authorization header of an outbound request."
[§WebClient Integration for Servlet Environments] "The ServletOAuth2AuthorizedClientExchangeFilterFunction provides a mechanism for requesting protected resources by using an OAuth2AuthorizedClient and including the associated OAuth2AccessToken as a Bearer Token."
[§RestClient Integration] "If an existing OAuth2AccessToken is expired, it is refreshed (or renewed)"
추출된 주장 (Claims Extracted)
Claim IDprefix:SPRING-AUTHZCLIENT.
| Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove |
|---|---|---|---|---|---|
| SPRING-AUTHZCLIENT-C1 | @RegisteredOAuth2AuthorizedClient 애노테이션은 OAuth2AuthorizedClientArgumentResolver가 처리하며, 이 리졸버는 OAuth2AuthorizedClientManager를 직접 사용해 서버측 보유 OAuth2AuthorizedClient(token holder)를 **조회(retrieve)**한다 |
[§Resolving an Authorized Client] "The @RegisteredOAuth2AuthorizedClient annotation is handled by OAuth2AuthorizedClientArgumentResolver, which directly uses an OAuth2AuthorizedClientManager and, therefore, inherits its capabilities." | official-vendor-doc |
컨트롤러 메서드 파라미터에 @RegisteredOAuth2AuthorizedClient("registrationId")를 선언해 OAuth2AuthorizedClient를 얻는 표준 조회 경로 |
OAuth2AuthorizedClientService를 이용한 대안 조회 경로(HttpServletRequest 컨텍스트 밖)의 상세 동작까지는 이 문장이 서술하지 않음 — annotation→ArgumentResolver→Manager 위임 관계만 직접 증명 |
| SPRING-AUTHZCLIENT-C2 | OAuth2ClientHttpRequestInterceptor는 principal 이름을 access token과 연결(associate)하는 PrincipalResolver를 사용하며, 이를 통해 애플리케이션이 저장되는(stored) OAuth2AuthorizedClient의 scope(누구 소유인지)를 선택할 수 있다 |
[§Providing the principal] "OAuth2ClientHttpRequestInterceptor uses a PrincipalResolver to determine which principal name is associated with the access token, which allows an application to choose how to scope the OAuth2AuthorizedClient that is stored." | official-vendor-doc |
RestClient + OAuth2ClientHttpRequestInterceptor 경로, 기본 SecurityContextHolderPrincipalResolver 또는 RequestAttributePrincipalResolver 구성 |
저장 매체(HttpSession 등 구체 구현체)는 이 문장이 명시하지 않음 — "저장된다(is stored)"는 사실과 principal-scope 사실만 증명. 브라우저가 access token을 절대 보유하지 않는다는 명제 자체를 이 문장이 직접 서술하지는 않음(그 명제는 branch 상속 결정 DEC-KEYCLOAK-PATTERNS-OVERVIEW-BFF-SESSION-001@1의 범위이며, 이 자료는 그 설계와 정합적인 "서버측 저장·스코프" 사실만 뒷받침) |
| SPRING-AUTHZCLIENT-C3 | RestClient용 OAuth2ClientHttpRequestInterceptor는 outbound request의 Authorization 헤더에 Bearer 토큰을 배치해 보호된 리소스 요청을 가능하게 한다 |
[§RestClient Integration] "This interceptor provides the ability to make protected resources requests by placing a Bearer token in the Authorization header of an outbound request." | official-vendor-doc |
RestClient + OAuth2AuthorizedClientManager 기반 구성(RestClientConfig 예제) |
WebClient 경로에는 적용되지 않음(별개 클래스 — C4 참조). 캐시된 access token을 우선 재사용하는지, 매 요청마다 토큰 조회 비용이 있는지 등 내부 캐싱 세부사항은 규정하지 않음 |
| SPRING-AUTHZCLIENT-C4 | ServletOAuth2AuthorizedClientExchangeFilterFunction은 OAuth2AuthorizedClient를 사용해 보호된 리소스를 요청하는 메커니즘을 제공하며, 연관된 OAuth2AccessToken을 Bearer Token으로 포함시킨다 |
[§WebClient Integration for Servlet Environments] "The ServletOAuth2AuthorizedClientExchangeFilterFunction provides a mechanism for requesting protected resources by using an OAuth2AuthorizedClient and including the associated OAuth2AccessToken as a Bearer Token." | official-vendor-doc |
Servlet 환경에서 WebClient + ExchangeFilterFunction 구성 — BFF가 downstream Resource API를 WebClient로 호출하는 proxy fan-out 시나리오의 직접 근거 |
@RegisteredOAuth2AuthorizedClient로 명시 전달하거나 clientRegistrationId 속성으로 지정한 client에 한정된 서술 — setDefaultOAuth2AuthorizedClient(true) "default" 동작(모든 요청에 동일 principal 토큰이 첨부되는 위험)은 이 문장이 아니라 별도 경고 문단("Be cautious…")의 범위이며 이 claim으로 그 위험까지 정당화하지 않음 |
| SPRING-AUTHZCLIENT-C5 | 기존 OAuth2AccessToken이 만료된 경우, (RestClient interceptor 경로에서) 자동으로 refresh(또는 renew)된다 |
[§RestClient Integration] "If an existing OAuth2AccessToken is expired, it is refreshed (or renewed)" | official-vendor-doc |
OAuth2AuthorizedClientManager가 refresh 수행 가능한 OAuth2AuthorizedClientProvider(예: refresh-token provider)를 구성한 RestClient 요청 경로 |
refresh_token 자체가 만료·폐기되어 refresh 시도가 실패하는 경우의 동작은 이 문장이 규정하지 않음(그 경우는 "Handling Failure"/OAuth2AuthorizationFailureHandler의 별개 관심사이며 이 raw 문서에는 발췌 대상 quote로 포함하지 않았다 — §관련 참조). WebClient 경로의 동일 자동 refresh 문구("if an OAuth2AuthorizedClientProvider is available to perform the authorization")는 이 인용과 다른 문장이며 이 claim 범위 밖 |
적용 경계 (Usage Boundaries)
- 이 자료가 직접 증명하는 것:
SPRING-AUTHZCLIENT-C1:@RegisteredOAuth2AuthorizedClient애노테이션 →OAuth2AuthorizedClientArgumentResolver→OAuth2AuthorizedClientManager위임 관계로 서버측OAuth2AuthorizedClient를 조회하는 공식 메커니즘 존재SPRING-AUTHZCLIENT-C2: authorized client가 principal에 scope되어 "저장된다"는 사실SPRING-AUTHZCLIENT-C3,C4: RestClient/WebClient 각각에서 저장된 access token을 Bearer 헤더로 첨부하는 공식 메커니즘 존재SPRING-AUTHZCLIENT-C5: 만료된 access token의 자동 refresh(renew) 동작
- 이 자료가 증명하지 않는 것 (UNSUPPORTED_DECISION 후보 — branch 구현 가이드에 그대로 인용 금지, 아래 세부사항은 branch-spec 단계에서 근거 보강 또는 라벨링 필요):
- "browser 는 access/refresh token 을 절대 보유하지 않는다"는 명제 자체 — 이 페이지는 서버측 조회·저장·스코프 메커니즘만 서술할 뿐, 브라우저가 무엇을 받는지(session cookie만인지)는 전혀 언급하지 않는다. 이 명제는
oauth2Login()의 자체 동작(어떤 응답에 무엇을 내려주는지)에 대한 별도 공식 근거(servlet/oauth2/login/섹션)가 필요하다. OAuth2AuthorizedClientRepository/OAuth2AuthorizedClientService의 기본 구현(예:HttpSessionOAuth2AuthorizedClientRepository)이 실제로HttpSession에 저장한다는 클래스명·직렬화 방식 — 이 페이지 범위 밖(별도 core/Javadoc 페이지 소관). 본 raw 자료는 "Handling Failure" 절의OAuth2AuthorizedClientRepository/Service구분 예제를 포함하지만, 그 절의 문장을 quote로 발췌하지 않았으므로 Repository vs Service의 request-scope 차이는 claim으로 등재하지 않는다.- refresh token 자체의 rotation 정책(1회용 여부, 재사용 감지) — 이 페이지는 access token 갱신 트리거만 서술하고 refresh token 자체의 lifecycle은 다루지 않음.
- "browser 는 access/refresh token 을 절대 보유하지 않는다"는 명제 자체 — 이 페이지는 서버측 조회·저장·스코프 메커니즘만 서술할 뿐, 브라우저가 무엇을 받는지(session cookie만인지)는 전혀 언급하지 않는다. 이 명제는
- 내 프로젝트(BFF, WI-010)에 적용하려면 추가 확인이 필요한 것:
- 실제
OAuth2AuthorizedClientRepository/Service기본 구현이HttpSession을 사용하는지 core.html/Javadoc으로 재확인. oauth2Login()이 인증 성공 시 브라우저에 실제로 무엇을 내려주는지(세션 쿠키만인지) 별도 공식 문서로 확인.- BFF의 실제 proxy controller가
@RegisteredOAuth2AuthorizedClient+RestClient/WebClient중 어떤 조합을 쓸지, 그리고 조회한OAuth2AuthorizedClient를 어느 인터셉터/필터에 넘길지 branch-spec 단계에서 결정.
- 실제
메모
검증되지 않은 내 해석. 사실 인용과 분리.
- C1이 "조회(retrieve)" 근거, C2가 "저장·스코프" 근거로 D2(토큰 holder) 결정을 함께 뒷받침한다(미검증 — branch-spec 작성 시 재확인).
- C3/C4 조합이 "held access token을 Bearer로 첨부해 downstream Resource API를 proxy"하는 구현 방식의 두 가지 후보(RestClient vs WebClient)를 제공한다. 어느 쪽을 BFF proxy 구현에 쓸지는 branch-spec 단계의 별도 결정 필요.
- C5가 "자동 refresh" 완료 조건의 직접 근거이나, refresh token 자체가 만료된 edge case는 "Handling Failure" 절(본 raw 자료에는 quote 미등재)과 별도로 다뤄야 한다.
- WebFetch(AI 요약 도구)의 1차 결과는 paraphrase되어 있어 verbatim 인용 소스로 부적합했다 — 원본 HTML을 직접 fetch(
curl)하여 태그를 제거한 순수 텍스트를source-fetch.txt로 사용했다(원문 바이트 보존, 요약 아님). - 추가로 봐야 할 동일 출처 페이지:
servlet/oauth2/client/core.html("Core Interfaces and Classes" —OAuth2AuthorizedClientRepository/Service기본 구현체 정의 추정),servlet/oauth2/login/index.html(oauth2Login이 브라우저에 내려주는 것).
관련
- 같은 주제 다른 official-doc / company-tech-blog: (아직 없음 — 이 branch의 최초 OAuth2 Authorized Client raw 자료)
- 이 자료를 인용한 wiki 요약:
[[wiki/concepts/...]](생성 시)