JWT(Json Web Token) 정리

시작하기

로그인을 개발하다보면 높은 확률로 JWT를 마주하게 된다.
그리고 면접에서도 자주 물어보는 질문들이 있는데, 이참에 한번 정리해보고자 한다.

JWT

우선 JWT란?

JWT(Json Web Token)는 JSON 형태의 클레임(claims)을 안전하게 전송하기 위한 토큰 규격이다.
사용자의 인증 상태나 권한 정보처럼 자주 참조되는 데이터를 토큰 자체에 담아서 전달할 수 있어서 추가 저장소 없이도 인증·인가 시나리오를 구현할 수 있는게 장점이다.

기본적으로는 HTTP 헤더나 쿠키, 혹은 쿼리 파라미터 등 다양한 통신 채널을 통해 활용할 수 있지만 대부분 헤더에 담아서 통신한다.

왜 사용할까?

  • Stateless 인증: 서버가 세션 상태를 기억하지 않아도 되기때문에 서버 확장 시 세션 동기화 문제를 걱정하지 않아도 된다.
  • 빠른 인가 판단: Payload에 필요한 정보를 담아두면 별도 DB 조회 없이도 사용자 권한을 판별할 수 있다.
  • 표준화된 포맷: RFC 7519에 정의된 표준이기 때문에 언어나 플랫폼에 상관없이 손쉽게 구현하고 검증할 수 있다.

JWT 구조

JWT는 Header.Payload.Signature 로 이루어져있고 각 부분을 .로 연결한 문자열이다.

각 부분은 Base64URL 방식으로 인코딩되며, 구조는 다음과 같다.

  • Header: 토큰 타입(typ)과 서명에 사용된 알고리즘(alg) 정보를 담는다.
  • Payload: 토큰에 담길 클레임을 기록한다. 예: 발급자(iss), 대상(sub), 만료 시간(exp), 사용자 정의 데이터 등
  • Signature: Base64UrlEncode(header) + '.' + Base64UrlEncode(payload)를 비밀 키 혹은 비대칭키로 서명한 값이다. 토큰 위·변조 여부를 판별할 때 사용된다.

왜 Base64URL 을 사용할까?

Base64URL은 일반 Base64를 URL·파일명·HTTP 헤더·쿠키 등에서 안전하게 사용할 수 있도록 문자를 치환하고 패딩을 제거한 문자열이다.
JWT는 전송 경로 제약이 큰 환경을 고려해 Base64URL을 채택한다.

  • 전송 경로 안전성: +/는 URL에서 의미가 있거나 일부 시스템에서 변형될 수 있기 때문에 Base64URL은 이를 -, _로 바꾸고 = 패딩을 생략해 URL·쿠키·헤더에서 안전하다.
  • 스펙 준수: JWT/JWS 스펙(RFC 7515, 7519)은 “base64url-encoding without padding”을 요구하는데 구현 간 일관성과 상호운용성이 높다.
  • 패딩 제거로 간결함: = 패딩을 없애 전송 바이트를 약간 줄이고 파싱 로직을 단순화한다.
  • 인코딩일 뿐 암호화 아니다: Base64URL은 가독성만 바꾸는 인코딩일 뿐이다. 기밀성은 제공하지 않으며, JWT의 보안 속성은 서명(무결성)에서 온다. 기밀성이 필요하면 JWE(암호화된 JWT)를 사용한다. (중요하다)

JWT

발급과 검증 흐름

  1. 사용자가 로그인하면 서버는 사용자 정보를 바탕으로 페이로드를 구성한다.
  2. 서버는 헤더·페이로드를 비밀 키(HS256 등) 혹은 개인 키(RS256 등)로 서명한 뒤 JWT를 만들어 클라이언트에 전달한다.
  3. 클라이언트는 이후 요청마다 JWT를 헤더에 담아 전송한다.
  4. 서버는 수신한 토큰을 디코딩하고 시그니처를 검증해 토큰의 무결성을 확인한다.
  5. 만료 시간과 필요한 클레임을 확인한 뒤, 요청을 처리하거나 거부한다.

리소스 서버(API)인증 서버(Auth)클라이언트(브라우저/앱)리소스 서버(API)인증 서버(Auth)클라이언트(브라우저/앱)사용자로그인 요청(이메일/비밀번호)1인증 요청(자격 증명)2사용자 검증 및 클레임 구성3JWT 발급(Access Token[+Refresh])4요청 + Authorization: Bearer <JWT>5헤더/페이로드 디코딩(Base64URL)6시그니처 검증(alg 제한, 키 조회/JWKS)7exp/nbf/iss/aud 등 클레임 검사8응답(허용/거부)9화면 렌더링10사용자

주의해야 할 부분

  • 민감 정보 저장: Payload는 Base64URL 인코딩만 되어 있으므로 누구나 쉽게 내용을 확인할 수 있다.
  • 강력한 비밀 키 관리 필요: 짧은 키나 유출된 키는 무작위 대입 공격에 취약하다. 안전한 비밀 키 관리 전략이 필수적이다.
  • 토큰 탈취 대응 전략: 토큰 저장소 선택(LocalStorage, Cookie 등)과 HTTPS 적용, Refresh Token Rotation, 탈취 감지 체계 등을 함께 고려해야 한다.
  • 만료 전략 설계: 토큰 갱신 주기가 너무 짧으면 사용자 경험이 나빠질 수 있고, 너무 길면 보안 리스크가 커지기 때문에 필요 시 슬라이딩 세션을 도입하거나 액세스·리프레시 토큰 조합을 사용한다.

추가로 알아두면 좋은 질문들 (JWT를 이해하고 활용할 때 아래와 같은 질문을 스스로 정리해 보면 도움이 된다.)

🔒 보안 심화

  1. JWT는 stateless한 인증 방식인데, 서버에서 강제 로그아웃이나 토큰 블랙리스트 처리를 구현하려면 어떤 설계가 필요할까요?
  2. Refresh Token 탈취가 발생했을 때, Access Token의 만료 주기와 연계해 피해를 최소화하는 전략은 무엇일까요?
  3. JWT 페이로드는 암호화되지 않습니다. 민감 정보(예: 이메일, 사용자 역할)를 포함해야 하는 상황이라면 어떤 방식으로 안전하게 담을 수 있을까요?

⚙️ 운영 및 설계

  1. JWT 길이가 길어져 모바일 환경이나 쿠키 전송에서 성능 문제가 생긴다면 어떤 최적화 방법이 있을까요?
  2. 서버가 여러 대일 때 서명 검증에 필요한 비밀 키를 분산 환경에서 동기화하는 방법(KMS, JWKS, Key Rotation 등)은 무엇이 있을까요?
  3. JWT 기반 인증에서 토큰 크기 증가와 DB 조회 최소화 요구사항이 충돌할 때 어떤 설계 선택을 할 수 있을까요?

🔑 Key & Rotation

  1. Key Rotation 시 기존 사용자 세션을 유지하면서도 새로운 키로 서명된 토큰만 허용하려면 JWT 검증 로직을 어떻게 설계해야 할까요?
  2. 여러 서비스(예: 마이크로서비스 아키텍처)에서 JWT를 공유해야 할 때 JWKS(JSON Web Key Set) 를 활용하는 방법은 무엇일까요?

🧩 응용 & 트러블슈팅

  1. JWT 기반 인증을 도입했지만 실제로는 서버에서 매 요청마다 사용자 정보를 다시 DB에서 조회하고 있습니다. 이 문제가 생기는 이유와 개선 방법은 무엇일까요?
  2. JWT를 HTTPS가 아닌 환경에서 사용한다면 어떤 공격 시나리오가 가능하고, 이를 막기 위한 최소한의 보안 대책은 무엇일까요?

결론

JWT 를 어떻게 관리하고 어떻게 통신할지 등에 대한 세부적인 내용은 구현방식에 따라 조금씩은 다를 수 있다.
하지만 이런 세부적인 내용을 제외하더라도 JWT 자체에 대한건 반드시 집고 넘어가야한다.