들어가며
Spring Security로 카카오 OAuth2 로그인을 붙이자마자 /login?error로 튕기는 문제를 만났습니다. 원인을 파고들어 보니 Spring Security가 최신 버전부터 기본으로 켜는 보안 기능 하나가 카카오와 맞지 않았던 것이었습니다.
오류 내용
카카오 로그인을 시도하면 인증에 실패하며 /login?error로 리다이렉트됐습니다.
원인
Spring Security 7.x가 PKCE(Proof Key for Code Exchange)를 자동으로 활성화하면서, 카카오 인증 요청에 code_challenge 파라미터를 함께 전송하고 있었습니다.
# 문제가 된 카카오 인증 URL
https://kauth.kakao.com/oauth/authorize?...&code_challenge=fN1F0q...&code_challenge_method=S256
카카오는 이 파라미터를 지원하지 않기 때문에 인증이 실패했습니다.
PKCE란?
PKCE는 OAuth2 인증 과정에서 중간자 공격을 방어하는 보안 기법입니다.
- 앱이 랜덤 값(
code_verifier)을 생성하고, 그 해시값(code_challenge)을 먼저 인증 서버에 전송합니다. - 인증 서버가
code발급 후, 앱이code와 원본 랜덤 값을 함께 전송합니다. - 인증 서버가 해시를 비교해 일치하면 토큰을 발급합니다.
주로 client_secret을 안전하게 보관할 수 없는 환경 — 모바일 앱, SPA — 에서 사용합니다.
해결 방법
application.yml의 카카오 등록 정보에 client-authentication-method: client_secret_post를 추가했습니다.
spring:
security:
oauth2:
client:
registration:
kakao:
client-authentication-method: client_secret_post
PKCE를 꺼도 보안에 문제없는 이유
PKCE는 client_secret을 안전하게 보관할 수 없는 환경에서 쓰는 대체 수단입니다. Spring Boot 백엔드가 있는 구조에서는 상황이 다릅니다.
| 환경 | 보안 방식 |
|---|---|
| 모바일 앱 / SPA | PKCE (코드 로직에 시크릿 노출 불가) |
| 백엔드 서버 | client_secret (서버에서만 보관, 외부 노출 불가) |
백엔드 서버 구조에서는 client_secret 자체가 이미 강력한 인증 수단이므로, PKCE 없이도 보안에 문제가 없습니다. 카카오 역시 서버사이드 앱에는 client_secret_post 방식을 권장합니다.
정리
- 최신 프레임워크가 기본으로 켜는 보안 기능이 항상 모든 연동 대상과 호환되는 것은 아닙니다.
- 에러 메시지만으로는 원인을 알기 어려울 때, 실제로 나가는 요청 URL을 직접 확인하는 것이 가장 빠른 진단 방법이었습니다.
- 보안 기능을 끄는 결정을 내릴 때는 "왜 이 기능이 필요한 환경과 필요 없는 환경이 나뉘는지"를 이해하고 판단하는 것이 중요합니다.
