질문1

**Q1) Redirect URL은 Resource Owner가 ID와 PW를 입력하고 리다이렉션이 될 경로잖아. 그리고 나는 redirect URL을 http:/localhost:8080/login/oauth2/code/google로 설정을 했어.

  1. 만약에 배포를 한다면 내가 배포한 도메인에 맞게끔 이 리다이렉트 URL을 바꿔야할까?

  2. Resource Owner를 리다이렉트 시킨 그 주소부터 스프링 시큐리티가 자동으로 authorization code를 가지고 accesstoken을 받고 사용자 정보까지 받아와주는거야?**

1. 배포를 한다면?

수정해야 한다. 만약 서비스 도메인이 https://myapp.com이라면, 구글 콘솔의 ‘승인된 리다이렉션 URI’ 항목에 https://myapp.com/login/oauth2/code/google을 추가로 등록해야 한다.

2. Spring Security OAuth2 Client 라이브러리가 대신해준다.

맞다. Spring Security OAuth2 Client 라이브러리가 대신해준다.

  1. AuthorizationCode 수신. 사용자가 구글 로그인을 마치고 리다이렉트 되면, URL 파라미터에 code=xxx형태의 인증 코드가 붙어있다. Spring Security의 OAuth2LoginAuthenticationFilter가 이 코드를 낚아챈다.
  2. AccessToken 교환. 필터는 이 코드를 들고 다시 Authorization Server에 접근하여 Authorization Code 줄게, AccessToken줘.라고 한다. (이때 Client Secret이 사용된다.)
  3. 사용자 정보 요청: AccessToken을 성공적으로 받으면, Spring Security는 즉시 이 토큰을 사용해 Resource Server에 접근하여 이메일, 이름 정보를 가져온다.
  4. 객체 생성: 최종적으로 가져온 정보는 OAuth2User 타입의 객체로 변환되어, SecurityContext 내부에 저장된다.

질문 2

Q2) 버튼에 URL을 명시할 때 왜 네이버의 진짜 로그인 화면 주소 https://nid.naver.com/oauth2.0/authorize가 아닌, /oauth2/authorization/naver url로 설정하는지?

1. /oauth2/authorization/naver의 정체: “스프링의 비밀 통로”

이 주소는 화면이 존재하는 주소가 아니다. Spring Security가 내부적으로 만들어둔 인터셉터 전용 가상 주소이다.

  1. 왜 직접 네이버로 안 가고 이 통로를 거칠까?

    만약 HTML에 네이버 로그인 주소를 직접 적으려면 아래와 같이 긴 주소를 하드코딩해야 한다.

    <a href="[https://nid.naver.com/oauth2.0/authorize?client_id=내아이디&response_type=code&redirect_uri=http://localhost:8080/login/oauth2/code/naver&state=랜덤난수](https://nid.naver.com/oauth2.0/authorize?client_id=%EB%82%B4%EC%95%84%EC%9D%B4%EB%94%94&response_type=code&redirect_uri=http://localhost:8080/login/oauth2/code/naver&state=%EB%9E%9C%EB%8D%A4%EB%82%9C%EC%88%98)">

    그런데, 이렇게 되면 client_id 같은 설정값이 HTML 소스 코드에 그대로 노출된다. 그래서 상위 페이지 소셜로그인 그림과 같이 스프링 시큐리티가 client_id, scope, state 파라미터를 자동으로 추가해서 /oauth2/authorization/naver로 보내면 그제야 스프링 시큐리티가 네이버의 진짜 로그인 화면 주소로 요청을 보내게 된다.

  2. 스프링 시큐리티가 대신 해주는 마법 (302 Redirect)

    사용자가 단순히 /oauth2/authorization/naver를 클릭하면 일어나는 일이다.

    1. 요청 수신: 스프링 서버가 요청을 받는다.
    2. URL 자동 조립: 스프링 시큐리티가 application.yml에 적어둔 설정 값(client-id, redirect-uri, scope)을 읽어와서, 네이버 진짜 로그인 주소에다가 붙인다.
    3. 302 리다이렉트 명령: 조립이 끝나면, 서버는 브라우저에게 HTTP 302 상태 코드와 함께, “자, 내가 주소 완벽히 만들어 놨으니 이제 진짜 네이버 주소로 이동해!”라고 응답을 보낸다.
    4. 네이버 이동: 브라우저가 그 명령을 받고 즉시 nid.naver.com 로그인 화면으로 이동한다.

질문3

  1. 3번 CustomOAuth2User라는 객체를 따로 만드는 이유가 기존 OAuth2User에는 PK와 Role과 같은 정보가 없으니까, CustomOAuth2User라는 객체에다가 JWT를 생성하고, 이후에 JWT를 이용하여 인증된 회원인지 구분하기 위해서 만들어주는거야?
  2. 그리고 로그인에 성공했을때, SecurityFilterChain내의 .successHandler(OAuth2LoginSuccessHandler)가 CustomOAuth2User라는 객체를 이용해서 JWT를 만들어주는거야?
  3. OAuth2LoginSuccessHandler 클래스를 정확히 구현해줘.
  4. 그리고 만들어준 accessToken(JWT)는 따로 저장을 해둘 필요가 없는게, 어차피 클라이언트가 헤더에 accessToken을 담아서 보내면 알아서 자동으로 payload를 계산해서 등록된 회원이지 판단해주는거야? 즉, 나는 그냥 만들어주고 보내고, refreshToken만 db에 저장하는 로직만 구현하면 돼?

1. CustomOAuth2User를 만드는 이유

👉 완벽하게 맞습니다.

스프링 시큐리티가 기본으로 제공하는 OAuth2User에는 '구글이 준 이름, 구글 이메일'만 있을 뿐, 정작 우리 서비스에서 가장 중요한 **'내 DB의 회원 번호(PK)'**와 **'회원 권한(Role)'**이 없습니다. 나중에 API 요청이 들어올 때 "아, 이 사람은 5번 회원이구나"라고 알아채려면 이 정보들을 JWT Payload에 넣어서 구워야 합니다. 즉, JWT를 굽기 위한 필수 재료(PK, Role)를 핸들러까지 안전하게 배달하기 위해 CustomOAuth2User라는 전용 바구니를 만드는 것입니다.

2. OAuth2LoginSuccessHandler의 역할

👉 이것도 정확합니다.

소셜 로그인이 성공적으로 끝나면, 스프링 시큐리티는 CustomOAuth2User 객체를 Authentication이라는 상자에 담아서 OAuth2LoginSuccessHandler에게 던져줍니다. 그러면 핸들러는 그 상자를 열어서 PK와 Role을 꺼낸 뒤, 그걸 재료 삼아 Access Token과 Refresh Token을 찍어내고 사용자(프론트엔드)에게 전달해 주는 최종 출구 역할을 합니다.