API 서버를 운영하다 보면 가장 골치 아픈 게 바로 "인증과 인가"입니다. 처음 백엔드를 시작했을 때 저는 세션 방식만 알고 있었는데, MSA 환경으로 넘어가면서 JWT와 OAuth 2.0를 본격적으로 다루게 됐습니다. 솔직히 말하면 처음엔 둘의 차이도 헷갈렸고, 토큰 만료 처리 때문에 새벽에 장애 대응한 적도 많았죠. 이 글에서는 제가 실무에서 직접 부딪히며 배운 API 보안의 핵심을 최대한 솔직하게 풀어보려 합니다.

목차

JWT의 동작 원리와 실전 활용

JWT는 왜 쓰는가

JWT(JSON Web Token)는 헤더, 페이로드, 서명 세 부분으로 이뤄진 토큰입니다. 가장 큰 매력은 "상태를 서버에 저장하지 않는다"는 점이에요. 세션 방식은 서버 메모리나 Redis에 세션 정보를 들고 있어야 하지만, JWT는 토큰 자체에 사용자 정보를 담아 검증만 하면 됩니다. 서버를 여러 대로 늘려도 세션 동기화 걱정이 없으니 확장성 면에서 정말 편했습니다. 실제로 트래픽이 몰리는 서비스에서 무상태(stateless) 구조 덕을 톡톡히 봤습니다.

실무에서 만난 함정

그런데 좋기만 한 건 아닙니다. 한번 발급한 JWT는 만료 전까지 강제로 무효화하기가 까다롭습니다. 사용자가 로그아웃하거나 계정이 탈취됐을 때 토큰을 즉시 막아야 하는데, 무상태라는 특성이 오히려 발목을 잡죠. 그래서 저는 액세스 토큰의 만료 시간을 짧게(15~30분) 두고, 리프레시 토큰을 별도로 관리하는 방식을 씁니다. 리프레시 토큰은 DB나 Redis에 저장해 두고 필요할 때 블랙리스트 처리합니다. 이 구조 덕에 보안과 편의성의 균형을 맞출 수 있었습니다.

OAuth 2.0의 구조와 인증 흐름

OAuth 2.0가 풀어주는 문제

OAuth 2.0는 "내 비밀번호를 제3자에게 주지 않고도 권한을 위임"하는 표준입니다. 구글 로그인, 카카오 로그인 같은 소셜 로그인이 전부 이 위에서 돌아갑니다. 핵심 등장인물은 리소스 소유자(사용자), 클라이언트(우리 앱), 인가 서버, 리소스 서버 네 가지예요. 사용자가 "이 앱이 내 프로필을 봐도 좋아"라고 동의하면 인가 서버가 액세스 토큰을 발급하고, 우리 앱은 그 토큰으로 자원에 접근합니다.

Authorization Code 흐름이 표준인 이유

OAuth에는 여러 그랜트 타입이 있지만, 웹·모바일에서는 Authorization Code 방식이 사실상 표준입니다. 토큰이 브라우저에 직접 노출되지 않고 백엔드 채널로 교환되기 때문이죠. 모바일이나 SPA라면 여기에 PKCE를 더해 코드 가로채기 공격까지 막는 게 요즘 권장 사항입니다. 처음 소셜 로그인을 붙일 때 Implicit 방식을 썼다가 보안 점검에서 지적받고 Authorization Code + PKCE로 갈아탄 경험이 있는데, 처음부터 표준을 따랐어야 했다고 후회했습니다.

JWT vs OAuth 비교와 실무 선택 기준

둘은 경쟁 관계가 아니다

가장 많이 하는 오해가 "JWT랑 OAuth 중 뭘 써야 하나요?"입니다. 사실 둘은 층위가 다릅니다. OAuth 2.0는 권한 위임의 "프레임워크"이고, JWT는 그 안에서 토큰을 표현하는 "포맷"입니다. 실제로 OAuth 인가 서버가 발급하는 액세스 토큰을 JWT 형태로 만드는 경우가 아주 흔합니다. 그러니 "OAuth로 인증 흐름을 설계하고, 토큰은 JWT로 표현한다"가 가장 현실적인 조합이에요.

한눈에 보는 장단점 비교

구분 JWT OAuth 2.0
역할 토큰 포맷·자체 인증 권한 위임 프레임워크
장점 무상태, 확장성 우수, 구현 단순 제3자 위임, 표준화, 소셜 로그인 적합
단점 즉시 무효화 어려움, 토큰 크기 큼 흐름 복잡, 초기 학습 비용 높음
대표 사용처 내부 API 인증, MSA 토큰 전달 소셜 로그인, 외부 API 연동

현업에서 통하는 API 보안 실전 팁

토큰 관리의 디테일

제가 실무에서 꼭 지키는 세 가지를 공유합니다. 첫째, 액세스 토큰은 짧게, 리프레시 토큰은 회전(rotation)시켜라. 리프레시 토큰을 한 번 쓸 때마다 새로 발급하고 기존 것은 폐기하면, 탈취되더라도 피해를 최소화할 수 있습니다. 둘째, 토큰은 HttpOnly·Secure 쿠키에 담아라. 로컬스토리지에 두면 XSS 한 방에 털립니다. 실제로 동료 팀이 로컬스토리지에 JWT를 보관했다가 사고가 날 뻔한 적이 있어요.

검증과 모니터링

셋째, 서명 알고리즘을 서버에서 강제하라. JWT의 alg 헤더를 none으로 바꾸거나 대칭키로 위조하는 공격이 실제로 존재합니다. 라이브러리 기본값을 믿지 말고 허용 알고리즘을 명시적으로 화이트리스트 처리하세요. 추가로 토큰 발급·검증 실패 로그를 꼭 남겨 이상 징후를 모니터링하는 걸 추천합니다. 이 작은 습관 하나가 침해 사고의 조기 발견으로 이어집니다. API 보안은 결국 이런 디테일의 누적이라는 걸 매번 느낍니다.

마무리: 누구에게 추천하는가

정리하자면, 내부 서비스 간 통신이나 단일 조직의 API 인증이라면 JWT 기반 무상태 인증이 가볍고 효율적입니다. 반면 외부 사용자에게 소셜 로그인을 제공하거나 제3자 앱에 권한을 위임해야 한다면 OAuth 2.0가 정답이고, 그 안의 토큰을 JWT로 표현하면 두 가지 장점을 모두 챙길 수 있습니다.

이 가이드는 특히 세션 방식만 써오다 MSA·소셜 로그인으로 넘어가는 주니어~중급 백엔드 개발자, 그리고 API 보안 구조를 처음부터 제대로 설계하려는 분에게 추천합니다. 완벽한 정답은 없지만, 토큰 수명·저장 위치·서명 검증 이 세 축만 단단히 잡아도 대부분의 사고는 막을 수 있습니다. 여러분의 서비스가 더 안전해지길 응원합니다!