"JWT만으로 충분할까?" 인증 설계에서 마주한 3가지 트레이드오프
2025. 5. 3. 15:18
728x90

웹 서비스에서 “로그인 기능”은 단순히 이메일과 비밀번호를 검사하는 것을 넘어서,
보안, 확장성, 사용자 경험 사이에서 끊임없이 선택해야 하는 설계의 연속입니다.
이번 글에서는 제가 직접 만든 auth-service를 개발하면서 마주한 설계 트레이드오프(Trade-off)에 대해 공유합니다.


1. JWT vs Session – Stateless와 제어 가능성 사이의 균형

초기 인증 구조를 설계할 때 가장 먼저 고민한 건 AccessToken을 Stateless하게 유지할 것인지,
아니면 서버 측에서 세션을 관리할 것인지였습니다.

  • JWT만 사용하는 구조는 서버가 상태를 저장하지 않아 API 확장성과 배포 편의성이 뛰어납니다.
    하지만 토큰이 유출되었을 때 로그아웃하거나 무효화하기가 어렵다는 보안적 단점이 있습니다.
  • 반대로 세션 기반 인증은 서버가 상태를 기억하기 때문에 로그아웃 처리, 사용자 제어, 중복 로그인 방지에는 유리하지만,
    서버 간 상태 동기화나 분산 구조에서는 불리합니다.
  • 결론적으로 저는 JWT를 기본으로 하되, Redis를 활용해 세션 개념을 부여했습니다.
    Redis에 로그인 세션마다 고유한 키를 저장하고, 이 키에 userAgent와 IP 정보를 함께 저장하여
  • 사용자 제어와 확장성을 동시에 잡을 수 있는 구조로 구성했습니다.

2. Redis vs Database – 속도와 영속성 사이의 선택

RefreshToken을 어디에 저장할지도 중요한 이슈였습니다.

  • Redis는 메모리 기반이기 때문에 빠르지만 휘발성이라는 특징이 있습니다.
    서버가 재시작되거나 Redis에 장애가 발생하면 토큰이 사라질 수 있는 리스크가 있습니다.
  • 반면 PostgreSQL 같은 RDB는 영속성이 보장되지만,
    토큰을 주고받을 때마다 디스크 IO가 발생해 성능 저하나 부하 가능성이 있습니다.
  • 저는 이 상황에서 속도를 우선시하기로 결정하고 Redis를 선택했습니다.
    대신 userId, userAgent, IP, expiredAt 정보를 함께 저장하여 보안성을 높이고,
  • 유실되었을 경우에는 로그인을 재요청하는 흐름으로 복구되도록 설계했습니다.

* 영속성 : 프로그램이 종료되어도 데이터가 사라지지 않고 지속적으로 저장되는 것을 의미


3. 사용자 경험 vs 보안 – 어느 정도까지 통제할 것인가?

처음에는 단순히 “로그인 → 토큰 발급”만 처리하는 구조였습니다.
하지만 생각보다 쉽게 중복 로그인, 탈취된 토큰의 재사용 문제가 발생할 수 있다는 걸 깨달았습니다.

이를 해결하기 위해 로그인 시 userAgentIP를 Redis 세션 키에 저장하고,
같은 userId가 다른 환경에서 로그인할 경우 기존 세션을 강제 만료시키는 구조로 설계했습니다.

  • 보안 면에서는 분명 효과적이었지만,
  • 사용자 입장에서는 “집에서 로그인했다가 회사에서 또 로그인했더니 자동 로그아웃됨” 같은 UX 이슈도 존재합니다.
  • 이 또한 트레이드오프였습니다.
  • 보안을 강화하면서도 UX를 최소한으로 해치지 않는 선에서 적용 범위를 좁히고,
    나중에 관리자 설정을 통해 선택적으로 제어할 수 있도록 구조를 확장할 계획입니다.

마치며

인증 기능은 단순해 보이지만, 실제 서비스를 운영한다고 가정했을 때
"보안 vs 속도", "제어 vs 확장성", "UX vs 안정성" 등 여러 선택의 기로에 놓이게 됩니다.

이번 auth-service 개발을 통해
단순히 “작동하는 코드”가 아닌 “현실을 반영한 구조”를 설계하는 경험을 할 수 있었습니다.
기능만 구현하는 데서 멈추지 않고, 왜 그렇게 설계했는지 설명할 수 있는 개발자가 되고자 합니다.


GitHub: github.com/Mirandalaw
프로젝트: auth-service

728x90
반응형