https://wo-dbs.tistory.com/348
[OAuth 2.0] 인가 엔드포인트 큰 흐름
인가 엔드 포인트를 개발하기 앞서 자세한 공부가 필요했으며 Spring Authorization Server의 코드를 분석하기 위해 큰 흐름을 다시 알 필요가 있었다. 다음 그림은 인가 엔드포인트의 순서대로 그림을
wo-dbs.tistory.com
큰 흐름에서의 분석

Spring Authorization Server 소스 코드에서 web 패키지의 OAuth2AuthorizationEndpointFilter의 클래스는 위 블로그에서 정리한 인가 엔드포인트 큰 흐름에서 순서 3번 18번까지 전체적인 흐름을 가지고 있다.
우선 OAuth2AuthorizationEndpointFilter 코드 중 doFilterInternal
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
//3qjs -
//이 요청이 /oauth2/authorize 인가? -> 아니면 그냥 통과, 맞으면 OAuth 인가 처리 시작
if (!this.authorizationEndpointMatcher.matches(request)) {
filterChain.doFilter(request, response);
return;
}
try {
//HTTP 요청 → OAuth 요청 객체로 변환 즉, 파싱만 하는 거임
// request.getParameter(“client_id”)
// request.getParameter(“redirect_uri”)
// request.getParameter(“response_type”)
Authentication authentication = this.authenticationConverter.convert(request);
if (authentication instanceof AbstractAuthenticationToken authenticationToken) {
authenticationToken.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
// OAuth 인가 로직의 시작 버튼
// 여기서 Provider가 호출됨
// Provider 안에서: client_id 검증, redirect_uri 검증 scope 검증, code 생성
Authentication authenticationResult = this.authenticationManager.authenticate(authentication);
// 유저가 로그인 안 돼 있으면 -> 로그인부터 하기 위해 Spring Security가 로그인 페이지로 보냄
if (!authenticationResult.isAuthenticated()) {
filterChain.doFilter(request, response); // 로그인 엔드포인트로 이동
return;
}
// OAuth 인가 코드 플로우에서 사용자 동의(consent)가 필요한 경우를 처리하는 분기
// 이 코드는 이 클라이언트가 scope들을 요청했는데 사용자가 아직 동의한 적이 없으면 -> 동의 화면으로 보내라라는 분기
if (authenticationResult instanceof OAuth2AuthorizationConsentAuthenticationToken authorizationConsentAuthenticationToken) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Authorization consent is required");
}
sendAuthorizationConsent(request, response,
(OAuth2AuthorizationCodeRequestAuthenticationToken) authentication,
authorizationConsentAuthenticationToken);
return;
}
this.sessionAuthenticationStrategy.onAuthentication(authenticationResult, request, response);
//성공하면 redirect
this.authenticationSuccessHandler.onAuthenticationSuccess(request, response, authenticationResult);
}
catch (OAuth2AuthenticationException ex) {
if (this.logger.isTraceEnabled()) {
this.logger.trace(LogMessage.format("Authorization request failed: %s", ex.getError()), ex);
}
//실패하면 error
this.authenticationFailureHandler.onAuthenticationFailure(request, response, ex);
}
}
Filter
Filter 부터 공부해보자
Filter는 HTTP 요청과 응답을 가로채서 컨트롤러에 도달하기 전/후에 공통 처리를 할 수 있는 관문
여기서 Filter를 쓰는 이유는
“/oauth2/authorize 요청이 들어왔을 때 OAuth 인가 흐름 전체를 ‘조율’하는 관문(오케스트레이터)”다. 즉, 요청을 받아서 누가 언제 무엇을 하게 할지 정한다
웹 요청 흐름을 아주 단순화하면
Client
→ Tomcat
→ Servlet Filter Chain ← ★ Filter는 여기
→ DispatcherServlet
→ Controller
→ Service
→ Response
위와 같이 진행된다.
Filter는 Controller 보다 앞단, 요청/응답을 가로채서 뭔가 할 수 있는 위치
원본 코드인 OAuth2AuthorizationEndpointFilter 소스 파일의 역할을 다음과 같다
/oauth2/authorize 요청을 OAuth 인증 흐름으로 변환하는 전용 Filter
이 Filter 하나가 아래를 전부 담당함
- 이 요청이 OAuth 인가 요청인지 판별
- HTTP 요청을 OAuth 내부 객체로 변환
- 검증 로직에게 위임
- 성공 시 redirect
- 실패 시 RFC 규칙에 맞는 error 응답
이 Filter가 직접 하지 않는 것은 다음과 같다.
- client_id 검증
- redirect_uri 검증
- scope 검증
- code 생성
- DB 조회
3번 브라우저의 GET or POST
브라우저 → 인가 서버
GET /oauth2/authorize?response_type=code&client_id=...
여기서부터 OAuth2AuthorizationEndpointFilter가 동작 시작
if (!authorizationEndpointMatcher.matches(request)) {
filterChain.doFilter(request, response);
return;
}
- /oauth2/authorize 요청을 가로채는 첫 관문
4번 ~ 7번
4번 → 로그인 페이지(응답) - 브라우저와 인가 서버 통신
5번 → 브라우저의 이동(요청) - 브라우저와 인가 서버 통신
6번 → 인가 서버(응답) - 브라우저와 인가 서버 통신
7번 → 로그인 페이지 보임 - 리소스 소유자 && 브라우저
로그인 안 된 상태 → 로그인 페이지로 리다이렉트
// OAuth 인가 로직의 시작 버튼
// 여기서 Provider가 호출됨
// Provider 안에서: client_id 검증, redirect_uri 검증 scope 검증, code 생성
Authentication authenticationResult = this.authenticationManager.authenticate(authentication);
// 유저가 로그인 안 돼 있으면 -> 로그인부터 하기 위해 Spring Security가 로그인 페이지로 보냄
if (!authenticationResult.isAuthenticated()) {
filterChain.doFilter(request, response); // 로그인 엔드포인트로 이동
return;
}
“아직 로그인 안 됐네? → Security가 처리하게 넘긴다”
다음과 같은 일을 함
- 302 /login
- 로그인 HTML 응답
- 사용자 로그인
→ 이건 Spring Security 쪽 책임
11번 - 브라우저가 자동으로 이동(요청) - 브라우저와 인가 서버 통신
- 로그인 성공 후 다시 /oauth2/authorize로 복귀
GET /oauth2/authorize?...
Cookie: JSESSIONID=...
이 시점에서:
- 로그인됨
- 다시 OAuth2AuthorizationEndpointFilter 통과
이 구간에서 Filter는 이렇게 행동함:
12 ~ 14번
12번 -> 동의 화면으로 리다이렉트 - 브라우저와 인가 서버 통신
13번 -> 브라우저가 동의 페이지 요청 - 브라우저와 인가 서버 통신
14번 -> 인가 서버 동의 HTML (응답) - 브라우저와 인가 서버 통신
// OAuth 인가 코드 플로우에서 사용자 동의(consent)가 필요한 경우를 처리하는 분기
// 이 코드는 이 클라이언트가 scope들을 요청했는데 사용자가 아직 동의한 적이 없으면 -> 동의 화면으로 보내라라는 분기
if (authenticationResult instanceof OAuth2AuthorizationConsentAuthenticationToken authorizationConsentAuthenticationToken) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Authorization consent is required");
}
sendAuthorizationConsent(request, response,
(OAuth2AuthorizationCodeRequestAuthenticationToken) authentication,
authorizationConsentAuthenticationToken);
return;
}
이게 “동의 화면으로 리다이렉트” 구간
- 302 /oauth2/consent
- 또는 기본 HTML 동의 화면 응답
18번 - 인가 코드 발급! - 브라우저와 인가 서버 통신
동의 완료 → 인가 코드 발급 → 클라이언트로 리다이렉트
this.sessionAuthenticationStrategy.onAuthentication(authenticationResult, request, response);
//성공하면 redirect
this.authenticationSuccessHandler.onAuthenticationSuccess(request, response, authenticationResult);
여기서 최종적으로
302 Location:
<https://client.example.com/callback?code=...&state=xyz>
→ 인가 코드 발급의 마지막 문지기
'RFC > OAuth 2.0' 카테고리의 다른 글
| [OAuth 2.0] 인메모리 DB 사용자 테스트 (0) | 2026.02.04 |
|---|---|
| [OAuth 2.0] Spring Security 기본 설정(FilterChain + formLogin) (0) | 2026.02.04 |
| [OAuth 2.0] 인가 엔드포인트 큰 흐름 (0) | 2026.02.04 |
| [OAuth 2.0] Spring Security (0) | 2026.02.03 |
| [OAuth 2.0] 개발 프로젝트 (0) | 2026.02.03 |