오늘은 카카오 OAuth2 로그인을 연동하던 중 트러블 슈팅이 있었습니다.
로컬에서는 잘 되던 로그인이
배포 환경에서 제대로 진행되지 않았고, Nginx 리버스 프록시와 관련이 있을거라고 짐작을 하였습니다.
저희 서비스는 Cloudflare와 Nginx를 통해 HTTPS를 구현하였고, 구조는 아래와 같습니다.
🏗️ 전체 아키텍처
사용자 브라우저
↓ HTTPS (443)
Cloudflare (SSL 종료)
↓ HTTP (80)
Nginx (리버스 프록시)
↓ HTTP (8080)
Spring Boot
🔧 Nginx 리버스 프록시 설정
upstream springapp {
server 127.0.0.1:8080 fail_timeout=0;
}
server {
listen 80;
server_name techfork.shop www.techfork.shop api.techfork.shop;
# Cloudflare Real IP 설정
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
real_ip_header CF-Connecting-IP;
location / {
proxy_pass http://springapp;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https; # Cloudflare 환경에서는 https 고정
}
}
Nginx 설정은 terraform 코드로 위와 같이 되어있는데요. 차근차근 살펴보겠습니다.
각 설정의 의미
설정 역할
| upstream | 백엔드 서버 그룹 정의, fail_timeout=0은 실패해도 바로 재시도 |
| listen 80 | HTTP 80 포트 수신 (Cloudflare가 SSL 종료하므로) |
| set_real_ip_from | Cloudflare IP 대역 신뢰 설정 |
| real_ip_header CF-Connecting-IP | Cloudflare 헤더에서 실제 클라이언트 IP 추출 |
| proxy_set_header Host | 원본 요청의 Host 헤더 전달 |
| proxy_set_header X-Forwarded-Proto | 원본 프로토콜 정보 전달 (HTTPS) |
위와 같이 설정이 되어 있었는데 불구하고 문제가 생겼던 것입니다.
무엇이 문제였을까요?
🚨 문제 1: redirect_uri가 localhost로 생성됨
증상
- OAuth2 로그인 후 콜백에서 멈춤
- 카카오 개발자 콘솔에서 "redirect_uri 불일치" 에러
원인
Spring Security OAuth2 설정에서 {baseUrl} 플레이스홀더를 사용할 때:
spring:
security:
oauth2:
client:
registration:
kakao:
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
{baseUrl}은 Spring이 인식하는 자신의 주소로 치환됩니다.
Spring Boot는 자기 앞에 프록시가 있는지 모르기 때문에:
# Spring이 인식하는 자신의 주소
http://localhost:8080
# 실제 외부에서 접근하는 주소
https://api.techfork.shop
결과적으로 잘못된 redirect_uri가 생성됩니다:
# ❌ 잘못 생성된 redirect_uri
http://localhost:8080/login/oauth2/code/kakao
# ✅ 올바른 redirect_uri
https://api.techfork.shop/login/oauth2/code/kakao
그럼 어떻게 해결했을까요?
해결
application.yml에 추가:
server:
forward-headers-strategy: native
forward-headers-strategy란?
리버스 프록시 뒤에서 원본 요청 정보를 인식하게 해주는 설정입니다.
Nginx가 전달하는 헤더들:
proxy_set_header X-Forwarded-Proto https; # 원본 프로토콜
proxy_set_header X-Forwarded-Host $host; # 원본 호스트
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 클라이언트 IP
Spring Boot는 기본적으로 이 헤더들을 무시합니다 (보안상 이유).
forward-headers-strategy: native 설정은 Spring에게 "이 헤더들 신뢰해도 돼, 사용해"라고 알려주는 것입니다.
설정값 동작
| none | X-Forwarded 헤더 무시 (기본값) |
| native | 서블릿 컨테이너(Tomcat)가 처리 |
| framework | Spring Framework가 처리 |
OAuth2 로그인 흐름 비교
❌ forward-headers-strategy 설정 없을 때:
1. 사용자가 카카오 로그인 클릭
2. Spring이 카카오로 리다이렉트
→ redirect_uri=http://localhost:8080/login/oauth2/code/kakao
3. 카카오 로그인 성공
4. 카카오가 http://localhost:8080/... 으로 리다이렉트 시도
5. ❌ 실패 (localhost는 카카오 서버에서 접근 불가)
✅ forward-headers-strategy 설정 후:
1. 사용자가 카카오 로그인 클릭
2. Spring이 X-Forwarded-* 헤더를 읽어서 실제 주소 파악
3. Spring이 카카오로 리다이렉트
→ redirect_uri=https://api.techfork.shop/login/oauth2/code/kakao
4. 카카오 로그인 성공
5. 카카오가 https://api.techfork.shop/... 으로 리다이렉트
6. ✅ 성공!
설정 후 Spring이 인식하는 값 변화
// 설정 전
request.getScheme() → "http"
request.getServerName() → "localhost"
request.getServerPort() → 8080
// 설정 후
request.getScheme() → "https"
request.getServerName() → "api.techfork.shop"
request.getServerPort() → 443
디버깅 팁
실제로 어떤 redirect_uri가 생성되는지 확인하려면:
방법 1: 로그 레벨 조정
logging:
level:
org.springframework.security.oauth2: DEBUG
방법 2: 브라우저 개발자 도구
Network 탭에서 카카오로 가는 요청의 URL을 확인:
https://kauth.kakao.com/oauth/authorize?
client_id=xxx&
redirect_uri=여기를_확인&
response_type=code
🚨 문제 2: 쿠키 도메인 에러
증상
java.lang.IllegalArgumentException: An invalid domain [.techfork.shop] was specified for this cookie
OAuth2 로그인 성공 후 쿠키 설정 단계에서 에러가 발생했습니다.
원인
RFC 6265 표준에서는 쿠키 도메인 앞에 점(.)을 붙이면 안 된다고 합니다.
// ❌ 잘못된 코드
cookie.setDomain(".techfork.shop");
// ✅ 올바른 코드
cookie.setDomain("techfork.shop");
쿠키 도메인 동작 원리
설정값 적용 범위
| techfork.shop | techfork.shop, api.techfork.shop, www.techfork.shop 전부 |
| api.techfork.shop | api.techfork.shop만 |
점 없이 설정해도 서브도메인 전체에서 쿠키 공유가 가능합니다!
예전 방식 vs 현재 방식
# RFC 2109 (구버전) - 점 필요했음
.techfork.shop → 서브도메인 포함
# RFC 6265 (현재) - 점 없이
techfork.shop → 서브도메인 자동 포함
Tomcat 최신 버전은 RFC 6265를 따르기 때문에 앞에 점 붙이면 에러가 납니다.
해결
환경변수 수정:
# ❌ 잘못된 설정
SERVER_DOMAIN=.techfork.shop
# ✅ 올바른 설정
SERVER_DOMAIN=techfork.shop
또는 CookieUtil 코드 수정:
// ❌ 점을 붙이는 코드가 있다면 제거
cookie.setDomain("." + domain);
// ✅ 그대로 사용
cookie.setDomain(domain);
✅ 최종 체크리스트
Spring Boot 설정 (application.yml)
server:
forward-headers-strategy: native
domain: ${SERVER_DOMAIN:localhost}
spring:
security:
oauth2:
client:
registration:
kakao:
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
Nginx 설정
location / {
proxy_pass http://springapp;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https; # Cloudflare 환경
}
📝 요약
문제 원인 해결
| redirect_uri가 localhost | Spring이 프록시 뒤 주소를 모름 | forward-headers-strategy: native |
| 쿠키 도메인 에러 | RFC 6265에서 점(.) 금지 | SERVER_DOMAIN=techfork.shop |
'프로젝트 > Techfork' 카테고리의 다른 글
| [26/01/26] 오늘의 개발 일지 - iOS 전용 카카오 로그인 API 구현 및 사용자 API 구현 (0) | 2026.01.28 |
|---|---|
| [26/01/22] 오늘의 개발 일지 - 개발자 토큰 API 구현 및 Spring Security Testing 삽질 (2) | 2026.01.23 |
| [26/01/20] 오늘의 개발 일지 - CI에서 테스트 실행 및 통합 테스트 컨테이너 환경 개선 (1) | 2026.01.20 |
| [26/01/14] 오늘의 개발 일지 - 카카오 소셜 로그인 구현 (2) | 2026.01.15 |
| [26/01/10] 오늘의 개발일지 - 온보딩 API 수정, 테스트 코드 작성, 엔티티 생성 성능 최적화 (0) | 2026.01.11 |