요즘 대부분의 웹 서비스에서는
구글, 카카오, 네이버와 같은 OAuth 기반 소셜 로그인이 기본처럼 제공된다.
OAuth 2.0의 개념이나 Authorization Code Grant 흐름 자체는 이미 정리되어 있다.
하지만 실제 프로젝트에 이를 적용해보며 이런 궁금증이 생겼다.
이러한 궁금증이 생겼기에 이번 글에서는 OAuth 개념 설명보다는,
Spring 기반 백엔드 프로젝트에서 Redirect 방식 소셜 로그인을 어떻게 설계하고 구현했는지 실제 흐름을 중심으로 정리해보려고 한다.
참고 - OAuth 2.0 와 Authorization Code Grant 🔑
https://velog.io/@kinggusrl3/OAuth-2.0-%EC%99%80-Authorization-Code-Grant
내가 구현한 Redirect 기반 OAuth 로그인 흐름은 다음과 같다.
[1] 프론트 로그인 버튼 클릭
↓
[2] GET /auth/social/redirect?provider=google|kakao
↓
[3] 백엔드가 provider별 OAuth 인가 URL 생성
↓
[4] Authorization Server로 Redirect
↓
[5] 사용자 로그인 및 동의
↓
[6] GET /auth/social/callback/{provider}?code=&state=
↓
[7] 인가 코드로 Access Token 교환
↓
[8] userinfo API 호출
↓
[9] 소셜 계정 연결 / 신규 회원 생성
↓
[10] JWT 발급 (Access + Refresh)
↓
[11] Refresh Token → httpOnly 쿠키 저장
↓
[12] 프론트 콜백 URL로 Redirect
이 구조의 핵심은 OAuth는 외부 인증을 위임하고,
서비스는 내부 인증 ( JWT )은 우리가 직접 책임진다는 것이다.
OAuth 기반 소셜 로그인을 사용하기 위해서는
각 소셜 플랫폼에 OAuth 애플리케이션 등록이 선행되어야 한다.
이 과정은 단순한 설정이 아니라 우리 서비스가 해당 플랫폼의 OAuth Client임을 등록하는 절차이다.
예시
http://localhost:8080/auth/social/callback/google
이를 통해 발급받는 값은 다음 두 가지이다.
예시
http://localhost:8080/auth/social/callback/kakao
해당 값들은 이후 인가 코드 → 토큰 교환 단계에서
서버가 Authorization Server와 통신할 때 사용됨
프론트엔드에서는 소셜 로그인 버튼 클릭시 다음 요청만 백엔드로 전달한다.
GET /auth/social/redirect?provider=google
이 방식의 장점은 명확하다.
이 구조에서 OAuth 흐름의 시작점은 항상 백엔드가 된다.
내가 백엔드 개발자이기에 프론트를 최소한으로 건드는 해당 구조를 선택하게 되었다.
백엔드는 전달받은 provider 값에 따라 각 OAuth 제공자에 맞는 인가 URL을 직접 생성한다.
이때 포함되는 값은 다음과 같다.
state 값은 서버에서 생성하여 저장하고, 콜백 시 동일한 값인지 검증한다.
인가 URL이 완성되면 백엔드는
302 Redirect
응답을 통해 사용자의 브라우저를 Google 또는 Kakao 로그인 페이지로 이동시킨다.
이 시점부터 로그인, 비밀번호 입력, 동의 화면은 모두 provider의 책임 영역이다.
사용자가 인증과 동의를 완료하면 provider는 사전에 등록된 redirect URI로 다시 이동시킨다.
GET /auth/social/callback/{provider}
?code=xxxx
&state=yyyy
이 시점에서 전달되는 것은 Access Token이 아니라 인가 코드이다.
백엔드는 인가 코드를 이용해 provider의 토큰 발급 API에서 서버 간 통신을 수행한다.
이때 요청에는 다음 정보가 포함된다.
이 과정은 브라우저를 거치지 않는 서버 간 통신으로 이루어지며, Access Token은 외부에 노출되지 않는다.
발급받은 Access Token으로 각 provider의 사용자 정보 API를 호출한다.
이를 통해 다음과 같은 정보를 획득한다.
OAuth 로그인은 단순 로그인 기능이 아니라
계정 연결(account linking) 문제를 함께 고려해야 한다.
나는 다음과 같은 구조로 설계했다.
User
└── SocialAccount (provider, providerUserId)
처리 흐름은 다음과 같다.
1️⃣ provider + providerUserId 기준으로 조회
2️⃣ 기존 연동 계정 존재 → 해당 User 로그인
3️⃣ 연동 계정 없음 → 신규 User 생성
4️⃣ SocialAccount 저장 및 연결
이 구조를 통해:
가 가능해졌다.
OAuth 인증은 외부 인증일 뿐, 우리 서비스의 인증 체계는 JWT 기반이다.
따라서 소셜 로그인 성공 시:
을 직접 발급한다.
보안을 위해 Refresh Token은 다음 정책을 사용했다.
이를 통해 XSS 공격 시 토큰 탈취 위험을 줄이고, 재발급 API를 통한 갱신만 가능하도록 설계했다.
모든 인증 처리가 완료되면 백엔드는 프론트엔드 콜백 주소로 다시 redirect 한다.
성공 시:
/auth/callback?token=ACCESS_TOKEN
/auth/callback?error=LOGIN_FAILED
프론트는 이 토큰을 기준으로 로그인 상태를 유지한다.
즉, 외부 인증은 위임하되
서비스 보안과 세션 관리는 직접 설계한다.
이번 글에서는 OAuth Redirect 방식을 Spring 기반 프로젝트에서 실제로 어떻게 설계하고 구현했는지 흐름 중심으로 정리하였다.
단순히 소셜 로그인 구현이 아니라,
- OAuth 앱 등록
- Redirect 흐름 제어
- 인가 코드 교환
- 계정 연결 구조
- JWT 및 Refresh Token 전략
까지 함께 고민한 경험이었다.
OAuth는 라이브러리로 쉽게 붙일 수 있지만, 그 내부 흐름을 이해하고 설계 기준을 명확히 하는 것은 이후 인증 구조를 확장하는 데 큰 도움이 될 것이다 💯