본문 바로가기
Spring Security

[OAuth2] 내가 보려고 만든 OAuth2 흐름 정리

by 우주물고기 2025. 5. 16.
반응형

시간 순서대로

 

[1] 클라이언트가 로그인 버튼 클릭 -> 서버 요청

 

GET /oauth2/authorization/kakao

 

Spring Security가 필터 체인에서 처리,

OAuth2AuthorizationrequestRedirectorFilter가 동작

 

 

[2] 서버 : OAuth2AuthorizationRequest 객체 생성

OAuth2AuthorizationRequest authorizationRequest = OAuth2AuthorizationRequest
    .authorizationCode()
    .clientId("KAKAO_CLIENT_ID")
    .authorizationUri("https://kauth.kakao.com/oauth/authorize")
    .redirectUri("http://localhost:8080/login/oauth2/code/kakao")
    .scopes(Set.of("profile_nickname", "account_email"))
    .state("a9f21b0f-d01b-45e2-81a7-69a123123abc") // CSRF 방지용 랜덤
    .build();

 

이 부분은 개발자가 코드 짜는게 아니라 알아서 만들어줌.

application.properties나 야믈 파일에 저장해둔 정도 토대로.

 

 

 

 

 

[3] 서버 : 이 객체를 쿠키에 저장 (직렬화 되어서)

쿠키 이름 = oauth2_autho_request (내 코드에서)

{
  "clientId": "KAKAO_CLIENT_ID",
  "authorizationUri": "https://kauth.kakao.com/oauth/authorize",
  "redirectUri": "http://localhost:8080/login/oauth2/code/kakao",
  "scopes": ["profile_nickname", "account_email"],
  "state": "a9f21b0f-d01b-45e2-81a7-69a123123abc"
}

OAuth2 인증은 짧은 흐름 내의 요청-응답 사이클이기때문에,

세션이나 DB에 저장해 둘 것 없이

일시적으로 쿠키에 저장해두는 방식이 효율적임.

 

 

 

[4] 서버 : 카카오로 리디렉션 응답

HTTP/1.1 302 Found
Location: https://kauth.kakao.com/oauth/authorize?
  response_type=code&
  client_id=KAKAO_CLIENT_ID&
  redirect_uri=http://localhost:8080/login/oauth2/code/kakao&
  scope=profile_nickname account_email&
  state=a9f21b0f-d01b-45e2-81a7-69a123123abc

 

 

 

[5] 클라이언트는 카카오 인가 서버로 리디렉션됨.

카카오 로그인 화면이 뜨고, 로그인 + 동의 완료

 

 

[6] 카카오 -> 우리 서버로 콜백됨

카카오가 우리 서버로 GET 요청 보냄.

아까 우리가 등록한 redirect_uri로 인가 코드 &  state를 보냄

GET /login/oauth2/code/kakao?
  code=b0b5d88a32cf3c37c1f9&
  state=a9f21b0f-d01b-45e2-81a7-69a123123abc

 

 

 

[7] 서버 : 필터에서 해당 요청을 받음

-> 쿠키에서 authorizationRequest 복원

 

역직렬화 해서, state 파라미터값 비교해서,

일치하면 인가 코드가 유효하다고 판단하고

일치안하면 예외 발생시킴

 

 

 

[8] 서버 : 카카오 엑세스 토큰 얻기 위해 POST 요청 보냄

(이것도 Spring Security가 알아서 해주는 일)

(OAuth2LoginAuthenticationFilter가 인가 코드 갖고 카카오 토큰 발급 API로 POST 요청 보냄)

POST https://kauth.kakao.com/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
code=b0b5d88a32cf3c37c1f9&
client_id=KAKAO_CLIENT_ID&
redirect_uri=http://localhost:8080/login/oauth2/code/kakao

 

 

 

 

[9] 카카오 -> 서버로 엑세스 토큰을 JSON형태로 줌

{
  "access_token": "kakao-access-token",
  "token_type": "bearer",
  "refresh_token": "kakao-refresh-token",
  "expires_in": 21599,
  ...
}

 

 

[10] 서버 : 받은 엑세스 토큰을 (헤더로)같이 보내면서, 카카오 사용자 정보 달라고 요청

GET https://kapi.kakao.com/v2/user/me
Authorization: Bearer kakao-access-token

 

-> 사용자 정보 (nickname, email등) 받음

 

 

 

[11] 서버 : 받은 정보를 바탕으로 우리 서비스의 사용자 객체 (UserDetail)로 매핑함

->  DB에 사용자 등록or 업뎃

SecurityContextHolder에 인증 정보 등록

(무조건 넣고 봐야함)

(왜냐면 세션에 이 값을 저장하는게 기본값이기때문에, 세션기반 로그인이 동작하게 되는것)

 

 

 

[12] 로그인 성공 -> 최종 리디렉션

설정한 success URL로 리디렉션 시

 

 


거의 모든 일을 컨트롤러가 아닌 필터가 처리해주고 있는데,

로그인영역은 애초에 필터가 담당해야하는 영역임.

보안 필터는 로그인 인증 관련 핵심 처리 담당.

 

그렇다면 컨트롤러는 언제 등장하냐?

 

보통 인증 이후에 개입하게 됨.

사용자가 로그인 요청 -> 스프링 시큐리티 필터들 통과

-> 인증 완료 -> SpringContextHolder에 사용자 정

-> 그 다음부터!! 컨트롤러가 개입.

 

 

반응형