HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
✍🏻
Learnary (learn - diary)
/
OAuth2 - Code Grant

OAuth2 - Code Grant

progress
Done
Tags
Spring
Oauth2란OAtuh의 키워드OAtuh2 Code Grant 방식 [대표]oauth2 실습 전 사전 설정[kakao]SpringSecurity + OAuth2 실습 및 분석OAuth2AuthorizationRequestRedirectFilterOAuthLoginAuthentication

Oauth2란

외부에서 가입된 인증정보를 기반으로 인증하는 표준 인증 프로토콜이다.
이때, 서버에 패스워드없이도 권한을 위임받게 된다.
Oauth의 인증과정에서 서버는 사용자로부터 권한을 위임받아야 외부에서 가입된 인증정보를 엑세스 할 수 있다.
 

OAtuh의 키워드

Resource Owner - 서비스 이용 사용자 및 리소스 소유자
Client - 사용자를 대신하여 권한을 위임받아 외부에서 가입된 인증정보를 엑세스 하는 서버 (oatuh를 적용하는 서버)
Resource Server: 보호받는 리소스(가입된 인증정보 := 개인 민감정보)를 가지고 있으며 엑세스 토큰을 이용하여 접근한다. (카카오,네이버,페이스북, 구글 등의 서버를 가르킴)
Authorization Server: 클라이언트 및 리소스 오너를 성공적으로 인증 후 엑세스 토큰을 발급하는 서버 ( 카카오,네이버, 구글 등의 인증 서버)
Oauth 2.0 에서 Client는 Authorization Server에게 4가지 방법으로 토큰 발생을 요청할 수 있다.
 

OAtuh2 Code Grant 방식 [대표]

Authorization Code Grant [흔히 쓰이는 인증 방법]
notion image
가장 흔히 쓰이는 방법중 하나로, 외부에 가입된 민감정보들이 외부에 노출되지 않아 보완상 안전한 특징을 가진다.
 
매커니즘
  1. Authroization Request : 클라이언트는 사용자를 Authorization Server로 리디렉션
      • example) UI에 카카오로 가입 또는 네이버로 가입 버튼을 누르면 리디렉션이 된다.
      • 해당 과정에서는 uri에 여러 정보들을 포함하고 있다.
      https://kauth.kakao.com/oauth/authorize ?response_type=code &client_id=0492f15cb715d60526a3eb9e2323c559 &scope=profile_nickname%20profile_image &state=xI8tRNCSoeiAIw87NaUr5foPbhBhW2METzHDBK75jgo%3D &redirect_uri=http://localhost:8080/login/oauth2/code/kakao
      • 파라미터 의미
        • response_type — code 고정
        • client_id — Authorization Server에서 클라이언트를 식별하기 위한 식별키
          • 우리쪽 서버를 미리 네이버 또는 카카오에게 알려줘야 한다!
        • redirect_uri — Authorization Server에서 처리 완료 후 리다이렉션 하기 위한 URL
          • 우리쪽 서버 url이다.(현재는 local 서버를 가르키는 것을 알 수 있다(
        • scope — 클라이언트가 요구하는 리소스를 정의
          • 위예제에서는 프로필닉네임과 프로필이미지를 요청하고 있다.
        • state — 클라이언트는 임의의 문자열을 생성하여 CSRF 공격을 방지함
          • CSRF 공격을 방지하기 위한 키이다.
  1. Authorization Response: 클라이언트에서 요구하는 리소스에 대해 사용자의 동의를 받아, 외부에 인증된 가입자가 맞으면 우리쪽 서버로 일회성 승인 코드를 부여한다.
/login/oauth2/code/kakao ?code=jzcahTyqbAx4zs9pKfBDlGXmB36sPX2YJCNIIw0RKkW_ODsYTQpheSGABo17dHC5rXRD2Qopb9QAAAF76FELEg &state=xI8tRNCSoeiAIw87NaUr5foPbhBhW2METzHDBK75jgo%3D
  • code - accessToken을 교환하기 위한 승인코드
  • state - 위에서 CSRF 공격을 방지하기 위한 임이의 문자열
  1. Token Request: 일회성 코드를 기반으로 Authorization Server에서 토큰을 만들어달라고 요청한다
      • grant_type — authorization_code 고정
      • code — 앞 단계에서 전달 받은 코드
      • client_id — Authorization Server에서 클라이언트를 식별하기 위한 식별키
      • client_secret — 클라이언트 비밀키
      HTTP POST https://kauth.kakao.com/oauth/token Accept=[application/json, application/*+json] Writing [ {grant_type=[authorization_code], code=[jzcahTyqbAx4zs9pKfBDlGXmB36sPX2YJCNIIw0RKkW_ODsYTQpheSGABo17dHC5rXRD2Qopb9QAAAF76FELEg], redirect_uri=[http://localhost:8080/login/oauth2/code/kakao], client_id=[0492f15cb715d60526a3eb9e2323c559], client_secret=[oqoKOBecGMC45Uh7z7bmdtMJ0A4PSQ2l]} ] as "application/x-www-form-urlencoded;charset=UTF-8"
  1. Token Response — Access-Token 및 부가정보 획득
      • access_token — 리소스 요청에 필요한 토큰 (보통 짧은 생명주기를 지니고 있음)
      • refresh_token — Access-Token을 갱신하기 위한 토큰
 
 

oauth2 실습 전 사전 설정[kakao]

카카오 Oauth 사전 절차 과정 진행하기
Kakao Developers
카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.
Kakao Developers
https://developers.kakao.com/
Kakao Developers
 
  1. 상단 내 애플리케이션 항목으로 진입 후
      • 애플케이션 추가하여 생성 누른후 앱이름 마음대로 설정하고 사업자명도 아무렇게 설정
        •  
notion image
  1. 방금 만들 애플리케이션 누루면 왼쪽 메뉴바가 보일것이다.
      • 거기에서 카카오 로그인 진입 후 활성화 설정으로 OFF → ON으로 변경
      • Redirect Uri 등록 → http://localhost:8080/${api 설계 uri대로 작성하면 됨}
        • 또는 이렇게 입력함 http://localhost:8080/oauth2/code/kakao
      notion image
  1. 왼쪽 메뉴바에서 동의 항목으로 진입한다.
      • 개발 서버 인증에서 필요한 항목을 설정한다.
  1. 왼쪽 메뉴바에서 보안으로 넘어가서 Client Secret 키 생성한다.
      • 그 후 활성화 상태를 사용함으로 변경한다.

SpringSecurity + OAuth2 실습 및 분석

 
gradle 의존성 추가
// Spring Security implementation 'org.springframework.boot:spring-boot-starter-security:' // Oauth implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' // JWT implementation 'com.auth0:java-jwt:4.3.0'
 
yaml 설정
notion image
OAuth2 AutoConfigure 과정에서 어떤 3자 인증을 제공하며 어떤 url로 요청할지 등 yaml에 등록한 정보를 기반으로 다른 Authorization Server와 소통을 하게 된다.
notion image
내부 스펙을 보면 여러가지 컬럼이 있지만, 각 외부 Oauth2인증을 제공하는 사이트 문서를 보고 필요한 설정들만 해놓으면 된다.
 
Spring Security OAuth2 구현체에서는 CodeGrantFilter가 존재해 실제 코드 기반으로 외부 Authorization Server와 토큰을 교환한다.
notion image
 
SpringSercurity OAuth 매커니즘 분석
FilterChainProxy Filter 모습을 보면 3,4,5번째에 Oauth2xxxxxFilter가 2개 추가된 것을 볼 수 있다.
이제 FIlter마다 어떤일을 수행하는지 분석할 것이다.
notion image
 
 

OAuth2AuthorizationRequestRedirectFilter

OAuth2AuthorizationRequestRedirectFilter 에서는에서는 resolve 메소드를 호출하는 것을 볼 수있다.
notion image
내부에서 DefaultOauth2AuthorizationRequestResolver에 의해 redircet url을 리턴하고 사용자를 해당 외부 로그인 화면으로 이동시킨다. 실제 로그인 화면으로 이동시키는 html은 DefaultLoginPageGeneratorFilter가 만들어준다
이것이 oauth2 인증 전 사용자에게 보여지는 화면 html이다. [카카오 OAuth2 예]
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="description" content=""> <meta name="author" content=""> <title>Please sign in</title> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous"> <link href="https://getbootstrap.com/docs/4.0/examples/signin/signin.css" rel="stylesheet" crossorigin="anonymous"/> </head> <body> <div class="container"> <h2 class="form-signin-heading">Login with OAuth 2.0</h2> <table class="table table-striped"> <tr><td><a href="/oauth2/authorization/kakao">kakao</a></td></tr> </table> </div> </body> </html>
해당 html 부분을 <tr><td><a href="/oauth2/authorization/kakao">kakao</a></td></tr> 클릭하면 이런 외부 Authorization Server로 보낼 외부 페이지로 이동한다.
notion image
 
OAuth2AuthorizationRequestRedirectFilter에서 사용되는 resolver구현체는 DefaultOAuth2AuthorizationRequestResolver 이다.
public final class DefaultOAuth2AuthorizationRequestResolver implements OAuth2AuthorizationRequestResolver { ... @Override public OAuth2AuthorizationRequest resolve(HttpServletRequest request) { String registrationId = this.resolveRegistrationId(request); if (registrationId == null) { return null; } String redirectUriAction = getAction(request, "login"); return resolve(request, registrationId, redirectUriAction); } } private String resolveRegistrationId(HttpServletRequest request) { if (this.authorizationRequestMatcher.matches(request)) { return this.authorizationRequestMatcher.matcher(request).getVariables() .get(REGISTRATION_ID_URI_VARIABLE_NAME); } return null; } private void sendRedirectForAuthorization(HttpServletRequest request, HttpServletResponse response, OAuth2AuthorizationRequest authorizationRequest) throws IOException { if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(authorizationRequest.getGrantType())) { this.authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, request, response); } this.authorizationRedirectStrategy.sendRedirect(request, response, authorizationRequest.getAuthorizationRequestUri()); } }
registrationId를 뽑아내는 행위를 하는데 보통 Oauth2의 패턴은 /oauth2/authorization/{registrationId} 패턴의 URL 요청을 처리한다.
  • {registrationId} 부분에는 인증 Provider 식별키(kakako || naver || google 등)가 입력된다.
그리고 resolve가 정상적으로 반환되면 실제 sendxx 메소드에서 리디렉션 정보를 입력한다.
  • AuthorizationRequestRepository 인터페이스 구현체에는 application.yml 파일에 설정한 OAuth 연동 정보가 저장되어 있다.
  • 인증 Provider 식별키로 AuthorizationRequestRepository 인터페이스에서 OAuth 연동 정보를 가져옴
  • authorization-uri 주소로 사용자를 리다이렉트 시킴
 
 
그리고 이제 실제 oauth2인증을 진행하기 위해 해당 버튼을 누르게 되면 외부에서 인증 절차(카카오, 네이버, 구글 등의 페이지) 를 밟을 뷰가 보여질 것이다. 인증이 완료되면 Authorization Server(외부 카카오 인증 서버, 네이버 인증서버 등)가 우리 서버로 1회성 승인 code를 보내줄 것이다.
 
이제 그것을 기반으로 token을 요청하고 응답받게 되는데 스프링부트 oauth2 내부에서는 OAuthLoginAuthentication 객체가 이를 수행한다.
 

OAuthLoginAuthentication

위에서 언급했듯이 일회성 승인코드와 state값을 받게 된다.
code는 토큰을 교환하기 위한 우리가 만든 서버임을 사전에 등록했던 서버에게만 주는 것이고 state는 CSRF 공격을 막기위한 임의의 문자열이다.
notion image
 
attemptAuthentication 메소드 내부를 보면 AuthenticationManager, AuthenticationProvider 와 같은 SpringSecurity 기본 구조를 그대로 활용하고 있다.
notion image
notion image
실제 내부로 들어가 보면 provider에 의해 인증을 진행하고 있다.
notion image
notion image
provider 정보를 보면 3개의 provider 구현체들이 있다.
notion image
notion image
notion image
autenticate 메소드를 호출하는 내부 구현체를 따라가면
notion image
notion image
 
실제로 외부 Authorization 서버에서 부여받은 일회성코드를 기반으로 토큰 발행을 요청하게 되는 부분이다.
해당 부분에는 일회성 코드를 기반으로 토큰 발생을 요청시킬 수 있는 authorizationCodeAuthenticationProvider를 호출하게 되고 이름 그대로 (일회성)코드 기반으로 토큰을 발생시키는 것을 알 수 있다.
notion image
내부로 들어가보면 autenticate메소드 를 요청한다.
실제 토큰 발행 요청과 인증서버에 있는 정보 가져오기는 해당 메소드에서 모든 이루어지게 된다
실제 토큰 발행은 authorizationCodeAuthenticationProvider 구현체가 직접 수행한다.
notion image
해당 구현체(authorizationCodeAuthenticationProvider)는OAuth2LoginAuthenticationProvider 상위 객체인 AuthenticationProvider 하위 타입중 하나이다. [이름이 진짜 비슷하다. 주의]
notion image
실제로 CodeAuthenticationProvider를 보면 getTokenResponse 메소드를 호출하는 것이 일회성 코드 기반으로 엑세스 토큰을 가져온다.
notion image
OAuth2AccessTokenResponseClient는 상위 타입의 인터페이스이다 실제 호출은 DefaultAuthorizationCodeTokenResponseClient 에서 일어난다.
notion image
notion image
일회성 코드 기반으로 토큰 발행 요청을 하고 응답을 받은 후 인증 서버에 관련 정보를 가져오는 실제 로직이다.
토큰 기반으로 인증서버에 저장된 정보를 가져오게 된다. loadByUser 이름처럼 사용자를 서버로 적재하는 의미로 내부 로직을 보면 exchange에 호출이 이루어지고 있는 것을 확인할 수 있다.
notion image
토큰 방행이 완료되면 OAuth2User 객체에 사전에 카카오에서 필요한 정보들을 정확히 가져오며 yaml에서 설정한 파일 기반으로 요청한 것을 알 수 있다.
notion image
 
해당 인증과정에서 보면 provider, manager 뿐만 아니라 사용하는 객체들도 기존 SpringSecurity 객체들에서 확장한 것이다.
스프링 시큐리티 인증 플로우를 보면 대표적으로 UserNamePasswordToken 구현체를 사용하지만 oauth2에서는 Oauth2AuthenticationToken을 사용하여 객체를 생성한다.
 
  • OAuth2User 상속구조
    • notion image
  • Oauth2AuthenticationToken 상속구조
notion image
실제로 Authentication 인터페이스를 구현한 객체들이 여러가지가 있는 것을 알 수 있고 oauth2 라이브러리를 추가함과 동시에 더많은 Token 구현체가 생긴것을 알 수 있다.
notion image
notion image
 
이렇게 하위 클래스에 모든 인증이 완료된 후에는 상위 클래스 successfulxxx 메소드를 호출하고
notion image
실제 successHandler에 의해 인증 성공을 완료한다.
notion image
 
여기까지가 기본적으로 제공하는 SpringOAuth2읜 구현체 인증 플로우다. - 끗 -
 
Next
[Security] - Oatuh2 Cookie Custom - Code Grant