본문으로 건너뛰기

결정-0014: 인증 세션은 DB 세션과 이중 전달(쿠키 · Bearer)로 한다

상태

승인됨. 결과 절의 마지막 항목만 결정-0022가 대체했으며 본 결정은 유효합니다.

맥락

M1 인증 구현 전에 세션 방식을 정해야 했습니다. 설계 문서에 "세션 방식은 M1에서 결정"이라는 예고만 있었고 결정은 없었습니다. 그마저 문서 재편 과정에서 유실되어 미결 항목이라는 표시조차 사라진 상태였습니다.

당시 전제는 다음과 같습니다. Spring Boot 4.1 모듈러 모놀리스와 PostgreSQL 위에서 same-origin 으로 배포하며(아키텍처 개요 7절), 인증 후 화면은 클라이언트 렌더링입니다(결정-0035). API 서버는 웹 전용이 아니며 향후 모바일 앱이 클라이언트로 추가될 수 있습니다. 이 전제가 논의의 중심이었습니다.

논의에서 확인한 사실

  • 액세스와 리프레시로 나누는 구조는 OAuth 2.0의 제3자 위임을 위해 만들어졌습니다. 리소스 서버가 클라이언트를 신뢰하지 않고, 리소스 서버와 인가 서버가 분리되어 매 요청 조회가 불가능한 상황을 전제합니다. "내 프론트엔드가 내 백엔드를 호출한다"를 위한 설계가 아닙니다.
  • SPA 확산기(2015~2020)에 자기 서비스 로그인에도 복사되었고, 그 배경에는 실질적 이유가 있었습니다. 프론트엔드와 API의 도메인 분리, 모바일 쿠키 처리의 번거로움, 무상태 확장 요구가 그것입니다.
  • 2023년 이후의 표준 권고는 브라우저 앱에 대해 세션 쿠키로 되돌아왔습니다. IETF의 OAuth 2.0 for Browser-Based Applications는 BFF 패턴을 권고합니다. 토큰은 서버가 들고 브라우저에는 HttpOnly 세션 쿠키만 내려줍니다.
  • 세션 저장 방식과 토큰 전달 방식은 직교합니다. 불투명 세션 토큰도 Authorization: Bearer 로 보낼 수 있습니다. 모바일이 요구하는 것은 Bearer 전달이지 JWT가 아닙니다.

검토한 대안

JWT 액세스 토큰과 불투명 리프레시 토큰(DB 저장)

정석적인 구성이며 액세스 토큰 수명 동안 DB 조회를 아낍니다. 요청 100회에 조회 1회입니다. 기각 사유는 아래 표가 담습니다.

JWT를 쿠키에 담는다

XSS 방어는 얻지만 즉시 무효화 불가는 그대로 남습니다. 그것은 전달 방식이 아니라 JWT의 본질이기 때문입니다.

DB 세션과 이중 전달 (채택)

핵심은 DB에 불투명 토큰을 두는 것이 세 안에서 모두 같다는 점입니다. 차이는 그 위에 JWT 액세스 레이어를 얹느냐 하나뿐입니다.

액세스 레이어가 필요한 조건 본 시스템의 상황
리소스 서버가 여러 개이며 각자 독립 검증 해당하지 않습니다. 모듈러 모놀리스입니다
제3자에게 API 개방 아직 해당하지 않습니다
프론트엔드와 API가 다른 도메인 해당하지 않습니다. same-origin 전제입니다
DB 조회가 병목이 될 트래픽 아직 해당하지 않습니다. 인덱스 조회 1회이며 캐시가 가능합니다

반면 즉시 무효화가 필요한 요구사항이 이미 셋 있습니다. 비밀번호 변경 시 다른 세션 정리(PROF-03)와 로그아웃, 기기 관리가 그것입니다.

결정

  1. 세션은 session 테이블에 저장합니다. 토큰은 불투명한 난수이며 그 자체에 정보를 담지 않습니다.
  2. 전달은 두 경로를 지원합니다. 웹은 HttpOnly Secure SameSite 쿠키를 쓰며 JS가 접근할 수 없어 XSS로 탈취되지 않습니다. 모바일과 외부 클라이언트는 Authorization: Bearer <token> 을 씁니다. 세션 테이블은 하나이며 전달 방식만 다릅니다.
  3. 쿠키 경로에는 CSRF 방어를 둡니다. Bearer 경로는 해당하지 않습니다.
  4. 세션은 사용 시 만료를 연장하며 무효화는 행 삭제로 즉시 반영합니다.
  5. session 테이블에 ipAddress 와 userAgent 를 두어 기기 목록과 개별 로그아웃의 기반으로 삼습니다.

재검토 조건

  • 서비스를 여러 개로 분리하거나 외부 개발자에게 API를 개방할 때 이 세션 테이블 위에 JWT 액세스 레이어를 얹습니다. 세션 토큰이 곧 리프레시 토큰 역할을 하므로 재작성이 아니라 추가입니다.
  • 세션 조회가 실제 병목으로 측정되면 캐시를 앞에 두고, 그래도 부족하면 위 전환을 검토합니다.
  • 인증 후 화면을 서버 렌더링으로 전환하는 경우에는 쿠키 방식이 그대로 동작하므로 본 결정이 제약이 되지 않습니다.

결과

  • 로그아웃과 비밀번호 변경, 기기 관리가 즉시 반영됩니다.
  • 클라이언트가 토큰 하나만 다루면 됩니다. 401 인터셉터와 재발급, 중복 갱신 방지가 필요 없습니다.
  • 감수하는 것은 요청마다 발생하는 세션 조회 1회입니다. 액세스 토큰 레이어가 아끼는 몫을 포기합니다.
  • account 테이블의 소셜 제공자 토큰 필드는 본 결정과 무관하게 유지될 예정이었으나, 결정-0022가 그 칸 자체를 없앴습니다.
© 2026 dev.goraebap