Spring Security + JWT 인증 설계 가이드
그래서 운영 가능한 JWT 설계는 토큰 포맷보다 정책으로 결정됩니다.
인증과 인가를 분리해야 합니다
흔한 실수는 토큰 파싱이 끝나면 보안 설계도 끝난 것처럼 보는 것입니다.
인증은 다음 질문에 답합니다.
- 이 호출자는 누구인가
- 제시된 자격이 유효한가
인가는 다음 질문에 답합니다.
- 이 호출자가 무엇을 할 수 있는가
- 어떤 리소스에 접근할 수 있는가
- 역할, 소유권, tenant 경계, 정책이 어떻게 결합되는가
JWT는 인증 상태를 운반하는 데 도움을 주지만, 권한 모델 자체를 대신해주지는 않습니다.
Access Token은 짧게 가져가야 합니다
Access Token은 짧은 요청 구간을 위한 증표로 봐야지, 사실상의 장기 세션으로 보면 위험합니다.
짧은 TTL은 다음 상황에서 노출 범위를 줄여줍니다.
- 토큰이 로그나 클라이언트 환경에 노출될 때
- 역할과 권한이 변경될 때
- 이상 사용이 탐지될 때
대신 access token이 짧아질수록 refresh token 정책이 더 중요해집니다.
Refresh Token은 더 엄격하게 다뤄야 합니다
많은 시스템이 access token은 신중하게 다루면서 refresh token은 느슨하게 관리합니다. 실제로는 반대여야 합니다.
Refresh Token 정책은 최소한 다음에 답해야 합니다.
- 어디에 저장할 것인가
- rotation을 강제할 것인가
- 재사용 탐지는 어떻게 할 것인가
- 기기/세션 바인딩은 어떻게 할 것인가
- 강제 로그아웃 시 어떻게 무효화할 것인가
refresh 전략이 약하면 JWT는 결국 통제 없는 장기 세션으로 변합니다.
필터 체인 책임은 깔끔하게 나눠야 합니다
Spring Security에서 유지보수가 어려워지는 대표 이유는 하나의 필터가 토큰 파싱, 사용자 로딩, 인증 객체 생성, 권한 판정, 오류 응답까지 모두 떠안기 시작할 때입니다.
더 건강한 구조는 다음을 분리합니다.
- 로그인 또는 자격 교환
- 토큰 추출과 검증
- 인증 객체 생성
- 인가 규칙
- authentication / access denied 오류 처리
이렇게 해야 보안 동작을 디버깅하고 진화시키기가 훨씬 쉬워집니다.
권한 변경 반영 전략을 명시해야 합니다
JWT 시스템은 로그인 시점보다, 로그인 이후 권한이 바뀌는 순간 더 자주 흔들립니다.
팀은 최소한 다음을 정해야 합니다.
- 기존 access token은 만료 시점까지 유효한가
- 역할 변경은 refresh 이후에만 반영되는가
- 어떤 이벤트가 refresh token 무효화를 강제하는가
- 비활성화 계정이나 탈취 의심 계정을 즉시 차단할 수 있는가
이 답이 모호하면 보안 사고와 운영 문의가 훨씬 어려워집니다.
폐기 전략도 실제 설계 대상입니다
완전히 stateless한 JWT는 이론적으로 매력적이지만, 현실 시스템은 보통 다음 이유로 어느 정도 revocation 제어가 필요합니다.
- 계정 탈취
- 다중 기기 로그아웃
- 관리자 강제 비활성화
- refresh token 재사용 탐지
이것이 매 요청마다 서버 조회를 뜻하는 것은 아니지만, 최소한 의도된 정책은 있어야 합니다. “JWT라서 폐기가 어렵다”는 설명은 정책이 아닙니다.
보안 오류 응답도 계약입니다
클라이언트는 다음 상태를 예측 가능하게 구분할 수 있어야 합니다.
- 인증되지 않은 요청
- 인증됐지만 권한이 없는 요청
- 만료되거나 손상된 토큰
- 차단되거나 비활성화된 사용자
필터 체인과 컨트롤러 계층의 오류 응답 형식이 제각각이면, 클라이언트와 운영자 모두 문맥을 잃습니다.
운영에서 자주 생기는 함정
다음 패턴은 실제로 많이 문제를 만듭니다.
- 지나치게 긴 access token TTL
- refresh token을 사실상 영구 세션처럼 운용
- 권한 변경 반영 정책이 불명확
- 인증 파싱과 비즈니스 인가를 한곳에 섞음
- refresh 실패율, 재사용 탐지, 이상 사용에 대한 관측이 없음
대부분의 JWT 문제는 서명 알고리즘보다 수명주기 정책에서 발생합니다.
체크리스트
운영 준비가 되었다고 하려면 최소한 다음이 명확해야 합니다.
- access token TTL이 의도적으로 짧은가
- refresh token 저장/rotation 정책이 정의됐는가
- 로그아웃과 강제 폐기 동작이 문서화됐는가
- 인가 규칙이 토큰 파싱과 분리되어 있는가
- 보안 오류 응답이 스택 전반에서 일관적인가
마무리
좋은 JWT 설계는 토큰 구조보다, 토큰 수명주기와 권한 변경 반영과 refresh 정책과 폐기 전략이 얼마나 명확하고 집행 가능한가에서 결정됩니다.
그 기준이 있어야 Spring Security + JWT 조합이 실전에서도 안전하게 유지됩니다.
Continue Reading
다음으로 읽기 좋은 글
실전에서 버티는 Spring Boot REST API 설계
Spring Boot REST API를 빠르게 만드는 방법이 아니라, 엔드포인트가 늘고 트래픽과 팀 규모가 커져도 경계가 무너지지 않도록 설계하는 기준을 정리합니다.
⚙️ BackendWebSocket 실시간 통신 설계 가이드
Spring Boot 기반 WebSocket과 STOMP를 도입할 때 필요한 연결 수명주기, 메시지 모델, 인증, 전달 보장, 운영 함정을 실무 관점에서 정리합니다.
💬 LanguagePython Service Layer 패턴 실전 적용
Python 애플리케이션에서 transport, 비즈니스 규칙, persistence 책임을 분리하는 실전 구조를 정리합니다.
🧪 TestSpring Boot 테스트 슬라이스: @WebMvcTest, @DataJpaTest
Spring Boot 테스트 슬라이스를 단순 어노테이션 모음이 아니라 테스트 피라미드와 실행 비용 관점에서 정리합니다. @WebMvcTest, @DataJpaTest, @JsonTest, @RestClientTest를 언제 쓰고 언제 @SpringBootTest가 더 맞는지 설명합니다.
다음 탐색