JWT 디코더 쉽게 이해하기 — 개념과 원리
JWT(JSON Web Token)는 사용자가 누구인지, 언제 만료되는지 같은 정보(클레임)를 로그인 서버와 애플리케이션 사이에서 주고받는 짧은 문자열입니다. 이 디코더는 토큰 안의 헤더, 페이로드, 만료 시각을 보여 줍니다. 로그인 오류를 디버깅하거나 서비스가 어떤 클레임을 보내는지, 토큰이 왜 거부되었는지 확인할 때 씁니다. 해독은 브라우저 안에서만 이루어지며 토큰은 어디에도 전송되지 않습니다.
계산 방법
서명된 JWT(JWS 간결 형식)는 점으로 구분된 세 부분, 즉 헤더.페이로드.서명으로 이루어집니다.
- 문자열을 점 기준으로 나눕니다.
- base64url을 표준 Base64로 바꿉니다. "-"는 "+"로, "_"는 "/"로 바꾸고 길이가 4의 배수가 되도록 "="를 붙입니다.
- Base64를 해독해 UTF-8 글자로 읽습니다. 첫 부분이 헤더, 둘째 부분이 페이로드입니다.
- 페이로드에 "exp"(1970-01-01 UTC 이후 초)가 있으면 날짜로 바꾸고, 이미 지났으면 "(expired)"를 붙입니다. 없으면 "—"로 표시합니다.
셋째 부분인 서명은 검증하지 않습니다.
원리
base64url은 암호화가 아니라 인코딩입니다. 3바이트를 URL에 안전한 4글자로 바꾸어 JSON을 헤더나 주소에 실어 보낼 수 있게 할 뿐이므로, 토큰을 가진 사람은 누구나 내용을 읽을 수 있습니다. JWT를 지키는 것은 "헤더.페이로드" 문자열 전체에 대해 계산한 서명입니다. HS256은 공유 비밀키로 만든 HMAC-SHA256이고, RS256·ES256은 공개키 서명입니다. 페이로드를 한 글자만 바꿔도 서명이 맞지 않지만, 이는 서명을 검증하는 쪽만 알아챌 수 있습니다.
예제 풀이
- 입력값은 "eyJhbGciOiJIUzI1NiIs…"로 시작하는 예시 토큰입니다.
- 첫 부분을 해독하면 헤더 {"alg":"HS256","typ":"JWT"}로, HMAC-SHA256으로 서명된 JWT입니다.
- 둘째 부분은 페이로드 {"sub":"1234567890","name":"John Doe","iat":1516239022}입니다.
- "iat"(발급 시각) 1516239022는 2018-01-18 01:30:22 UTC입니다.
- "exp" 클레임이 없으므로 만료 칸은 —입니다.
결과 해석
먼저 "alg"가 서버가 기대하는 알고리즘과 같은지 보고, "none"은 항상 거부해야 합니다. 주요 등록 클레임은 iss(발급자), sub(주체), aud(대상), exp(만료), nbf(유효 시작), iat(발급 시각), jti(토큰 ID)입니다. 수명이 짧은 액세스 토큰은 보통 몇 분에서 한 시간 안에 만료됩니다.
흔한 실수
- 서버에서 서명을 검증하지 않고 해독한 클레임을 그대로 믿습니다.
- 페이로드가 숨겨진다고 생각해 비밀 정보나 개인정보를 넣습니다.
- exp를 밀리초로 해석합니다. JWT의 시각은 초 단위입니다.
자주 묻는 질문
JWT는 암호화되어 있습니까?
일반적인 서명 JWT(JWS)는 암호화되지 않습니다. 암호화된 토큰은 다섯 부분으로 된 JWE 형식을 씁니다.
토큰이 왜 "eyJ"로 시작합니까?
JSON 객체를 여는 {" 뒤에 영문자가 오면 base64url로 바꾼 결과가 항상 "eyJ"로 시작하기 때문입니다.
여기서 서명을 검증할 수 있습니까?
없습니다. 검증에는 비밀키나 공개키가 필요하므로 서버 코드에서 관리되는 JWT 라이브러리로 해야 합니다.
출처: IETF RFC 7519, JSON Web Token (JWT) · IETF RFC 7515, JSON Web Signature (JWS) · IETF RFC 4648, The Base16, Base32, and Base64 Data Encodings