TIL - 20250911

juni·2025년 9월 11일

TIL

목록 보기
122/316

0911 Full-Stack: Advanced OAuth 2.0 and Token Management


✅ 1. 백엔드(BE): OAuth 2.0 로그인 흐름의 상세 구현

  • 단순히 소셜 로그인을 성공시키는 것을 넘어, 성공/실패 시의 후처리, 토큰 발급, 사용자 정보 동기화 등 실제 서비스에 필요한 상세 로직을 구현했습니다.

➕ 주요 컴포넌트 및 역할

  1. CustomOAuth2UserService:

    • 역할: OAuth 2.0 Provider(카카오 등)로부터 사용자 정보를 받아온 직후 실행되는 핵심 서비스입니다.
    • 기능: 받아온 소셜 정보(이메일, 닉네임 등)를 바탕으로, 우리 서비스의 데이터베이스를 확인합니다.
      • 기존 회원: 소셜 정보를 최신 상태로 업데이트합니다.
      • 신규 회원: 받아온 정보로 새로운 사용자 레코드를 생성하여 자동으로 회원가입시킵니다.
    • 결과적으로, Spring Security가 인증을 처리할 수 있도록 사용자 정보를 Principal 객체로 변환하여 반환합니다.
  2. OAuth2SuccessHandler (로그인 성공 핸들러):

    • 역할: CustomOAuth2UserService를 통해 인증이 성공적으로 완료되었을 때 호출됩니다.
    • 기능:
      • 우리 서비스의 독자적인 인증 토큰(JWT Access Token, Refresh Token)을 생성합니다.
      • 생성된 토큰을 클라이언트에게 직접 전달하는 대신, 보안 강화를 위해 Http-Only 쿠키에 담아 응답 헤더에 설정합니다. (Http-Only 옵션은 JavaScript로 쿠키에 접근하는 것을 막아 XSS 공격을 방지합니다.)
      • 마지막으로, 사용자를 프론트엔드의 특정 페이지(e.g., 메인 페이지)로 리다이렉트시킵니다.
  3. OAuth2FailureHandler (로그인 실패 핸들러):

    • 역할: OAuth 2.0 인증 과정 중 어떤 단계에서든 실패가 발생했을 때 호출됩니다.
    • 기능: 실패 원인을 로깅하고, 불필요한 쿠키를 정리한 후, 사용자를 프론트엔드의 에러 안내 페이지로 리다이렉트시킵니다.

✅ 2. 백엔드(BE): Access/Refresh Token을 이용한 인증 유지

  • Access Token은 수명이 짧아 보안에 유리하지만, 만료될 때마다 사용자가 다시 로그인해야 하는 불편함이 있습니다. 이를 해결하기 위해 수명이 긴 Refresh Token을 함께 사용하는 전략을 구현했습니다.
  1. Access Token 재발급 API:
    • 클라이언트가 Access Token 만료(e.g., 401 Unauthorized 에러)를 감지하면, 가지고 있던 Refresh Token을 이 API로 보냅니다.
    • 서버는 Refresh Token이 유효한지 검증한 후, 새로운 Access Token만 재발급하여 응답합니다.
  2. 로그아웃 API:
    • 로그아웃 요청 시, 서버는 클라이언트의 브라우저에 저장된 Access Token과 Refresh Token 쿠키를 모두 만료시켜 인증 상태를 완전히 종료합니다.

✅ 3. 프론트엔드(FE): 전역 인증 상태 관리 및 자동 토큰 갱신

  • 사용자의 로그인 상태를 앱 전반에서 일관되게 관리하고, Access Token이 만료되었을 때 사용자 모르게 자동으로 갱신하는 로직을 구현했습니다.

➕ 주요 개념

  1. 전역 상태 관리 (Zustand authStore):

    • 사용자의 로그인 여부, 프로필 정보 등을 전역 스토어에서 관리합니다.
    • 앱이 처음 로드될 때, 서버에 사용자 정보를 요청하여 스토어를 초기화합니다.
    • AppHeader와 같은 공통 레이아웃 컴포넌트에서 이 스토어를 구독하여, 로그인 상태에 따라 동적으로 UI(e.g., 프로필 아바타, 로그아웃 버튼)를 렌더링합니다.
  2. API 클라이언트와 인터셉터 (Interceptors):

    • 모든 API 요청을 한 곳에서 관리하기 위해 axios와 같은 API 클라이언트를 설정했습니다.
    • 요청 인터셉터: 모든 API 요청이 보내지기 전에 가로채서, 인증이 필요한 경우 자동으로 Access Token을 헤더에 추가합니다.
    • 응답 인터셉터: 모든 API 응답을 받은 후에 가로채서, 응답 상태 코드를 확인합니다.
      • 만약 401 Unauthorized 에러가 발생하면, 이는 Access Token이 만료되었다는 신호입니다.
      • 이때, 자동으로 Access Token 재발급 API를 호출합니다.
      • 새로운 Access Token을 성공적으로 받아오면, 실패했던 원래 요청을 새 토큰으로 다시 시도합니다. 이 모든 과정은 사용자 모르게 백그라운드에서 진행됩니다.
      • 재시도 중인 요청이 중복으로 발생하지 않도록 재진입 방지 로직을 추가하여 안정성을 높였습니다.
  3. 프라이빗 라우트 (Private Route):

    • 로그인이 필요한 페이지들을 감싸는 PrivateRoute 컴포넌트를 구현했습니다.
    • 이 컴포넌트는 전역 인증 스토어를 확인하여, 로그인 상태가 아니면 해당 페이지 대신 로그인 페이지로 리다이렉트시키는 라우트 가드 역할을 합니다.

📌 요약

  • 백엔드CustomOAuth2UserService를 통해 소셜 로그인 사용자를 우리 DB와 동기화하고, 성공/실패 핸들러를 통해 로그인 후의 흐름을 제어하며, Http-Only 쿠키로 안전하게 JWT를 전달하는 정교한 OAuth 2.0 파이프라인을 구축했습니다.
  • 프론트엔드Zustand를 이용해 전역 인증 상태를 관리하고, API 클라이언트의 인터셉터를 활용하여 Access Token의 자동 갱신 로직을 구현함으로써 사용자 경험을 크게 향상시켰습니다.
  • PrivateRoute 컴포넌트를 통해 사용자의 인증 상태에 따라 페이지 접근을 제어하는 선언적인 라우트 가드를 완성했습니다.

0개의 댓글