Programming/Spring

[Spring] JWT의 구조

_채채_ 2025. 10. 1. 23:59
JWT(JSON Web Token)는 헤더, 페이로드, 서명 이 세부분을 점(.)으로 구분하여 구성된 문자열이다.

1. 헤더 (Header) 📜

헤더는 토큰 자체에 대한 메타데이터를 담고 있다. 여기에는 주로 아래와 같은 두 가지 정보가 포함된다.

  • typ (Token Type): 토큰의 타입을 지정하며, JWT의 경우 항상 "JWT"라는 값을 가진다.
  • alg (Signing Algorithm): 서명을 생성할 때 사용한 알고리즘을 지정한다.  이 정보는 서버가 토큰을 검증할 때 어떤 알고리즘으로 서명을 확인해야 하는지 알려주는 중요한 역할을 한다.

2. 페이로드 (Payload) 📦

페이로드는 토큰이 실제로 전달하고자 하는 핵심 정보를 담고 있는 부분이다. 여기에 포함된 정보 조각들을 클레임(Claim)이라고 부르며, 클레임은 세 가지 종류로 나뉜다.

  • 등록된 클레임 (Registered Claims): JWT 사양에 이미 정의된 표준 클레임들로, 필수는 아니지만 사용을 권장하는 편이다.
    • iss (Issuer): 토큰 발급자
    • sub (Subject): 토큰의 주제 (사용자 ID 등)
    • aud (Audience): 토큰 대상자
    • exp (Expiration Time): 토큰 만료 시간 (NumericDate 형식, 예: 1480849147)
    • nbf (Not Before): 토큰 활성 날짜 (이 시간 전에는 토큰이 처리되지 않음)
    • iat (Issued At): 토큰 발급 시간
    • jti (JWT ID): 토큰의 고유 식별자
  • 공개 클레임 (Public Claims): 충돌을 방지하기 위해 URI 형식으로 이름을 짓는 클레임. 공개적으로 정의된 정보들을 포함할 때 사용된다.
  • 비공개 클레임 (Private Claims): 서버와 클라이언트 간에 협의 하에 사용하는 클레임. 사용자의 역할(role), 이름, 부서 등 애플리케이션에 필요한 정보를 자유롭게 추가할 수 있다.

3. 서명 (Signature) ✍️

서명은 이 토큰이 위변조되지 않았음을 확인하기 위한 것으로 서명은 다음 세 가지 요소를 조합하여 생성된다.

  1. Base64Url로 인코딩된 헤더
  2. Base64Url로 인코딩된 페이로드
  3. 서버만 알고 있는 비밀 키 (Secret Key)

이 세 요소를 헤더의 alg에 명시된 알고리즘(예: HS256)으로 해싱하여 생성한다.

 

<생성 방식>

HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload), secret
)

 

  • 위 두 개의 문자열 (Header + Payload)을 합쳐서 서명
  • 비밀 키(secret)를 사용해 서명 생성
  • 클라이언트가 받은 JWT가 서버에서 발급한 것인지 검증할 수 있음

서버는 클라이언트로부터 JWT를 받으면, 헤더와 페이로드를 동일한 비밀 키와 알고리즘으로 해싱하여 서명을 다시 계산한다. 그리고 이 계산된 서명 값과 토큰에 포함된 서명 값을 비교하여 일치하면 토큰이 신뢰할 수 있다고 판단하고, 일치하지 않으면 변조되었거나 유효하지 않은 토큰으로 간주하여 요청을 거부하는 것이다.

이러한 구조 덕분에 JWT는 자가 수용적(Self-Contained)이며, 서버가 별도의 저장소 조회 없이도 토큰 자체만으로 사용자 정보와 데이터의 무결성을 검증할 수 있게 해준다.


🆀 JWT를 사용하면 세션 관리가 필요 없을까?

일반적으로 JWT는 Stateless 인증 방식이기 때문에 서버에서 세션을 저장하지 않는다. 따라서 확장성이 좋고, 서버 간 세션 공유가 필요 없는 구조에 적합하다. 하지만 로그아웃, 토큰 만료 등의 관리가 어렵기 때문에 Refresh Token 전략이나 서버 측 블랙리스트 관리가 추가로 필요할 수 있다.