JWT 디코더
어떤 JSON 웹 토큰이든 디코딩해 헤더와 페이로드, 클레임을 읽기 쉬운 형태로 살펴보고, 필요하면 HMAC(HS256/384/512) 서명까지 검증하세요. 모든 처리는 브라우저 안에서만 이루어집니다.
JWT 디코더 사용 방법
- 1
토큰 붙여넣기
인코딩된 JSON 웹 토큰을 입력란에 붙여넣으세요. 디코더가 자동으로 헤더와 페이로드, 서명으로 나눠 줍니다.
- 2
클레임 확인하기
디코딩된 헤더와 페이로드를 보기 좋게 정리된 JSON으로 살펴보고, 만료 시각이나 발급 시각 같은 등록된 클레임을 읽기 쉬운 날짜로 확인하세요.
- 3
서명 검증하기
HMAC 토큰이라면 서명용 시크릿을 입력해 서명이 유효한지, 그리고 토큰이 변조되지 않았는지 확인하세요.
- 4
필요한 부분 복사하기
정리된 헤더나 페이로드 JSON을 클립보드에 복사해 테스트나 문서 작성, 디버깅에 활용하세요.
JSON 웹 토큰 이해하기: 구조와 클레임, 그리고 함정
점(.)으로 나뉜 세 부분
JSON 웹 토큰은 점(.) 두 개가 들어간 하나의 긴 문자열로, 이 점을 기준으로 헤더, 페이로드, 서명이라는 세 개의 세그먼트로 나뉩니다. 앞의 두 세그먼트는 각각 Base64URL로 인코딩된 작은 JSON 객체입니다. Base64URL은 Base64의 URL 안전 변형으로, 몇몇 문자를 바꾸고 패딩을 없애 토큰이 헤더나 쿼리 문자열에 깔끔하게 실려 전달되도록 합니다. 세 번째 세그먼트는 앞의 두 부분을 대상으로 계산된 서명입니다.
토큰을 붙여넣으면 디코더는 점을 기준으로 나눈 뒤 앞의 두 부분을 Base64URL 디코딩해 읽을 수 있는 JSON으로 되돌립니다. 그러면 발급자가 작성한 그대로의 헤더와 페이로드를 볼 수 있습니다. 이것이 애초에 가능한 이유야말로 뒤따르는 모든 이야기의 핵심입니다. 즉, 이 세그먼트들은 단지 인코딩되어 있을 뿐 암호화된 것이 아닙니다.
헤더: 알고리즘과 타입
헤더는 가장 작은 부분입니다. 보통 타입(JWT)을 선언하며, 더 중요하게는 alg 필드에 서명 알고리즘을 담습니다. 흔한 값으로는 공유 시크릿을 사용하는 HMAC 방식의 HS256, 그리고 개인 키로 서명하고 공개 키로 검증하는 비대칭 키 쌍 방식의 RS256이나 ES256이 있습니다. 알고리즘은 서명이 어떻게 만들어졌는지, 따라서 어떻게 검증해야 하는지를 검증자에게 알려 줍니다.
alg 필드는 보안과도 직결됩니다. 알고리즘이 none이라고 주장하는 토큰이나, 공격자가 비대칭 알고리즘의 토큰을 대칭 알고리즘으로 바꿔치기해 순진한 검증자가 공개 키를 HMAC 시크릿으로 쓰도록 속이는 수법은 고전적인 공격입니다. 제대로 된 검증자는 헤더에 적힌 값을 무턱대고 믿지 않고, 기대하는 알고리즘을 미리 고정해 둡니다.
페이로드와 등록된 클레임
페이로드는 클레임, 즉 토큰이 담고 있는 진술을 실어 나릅니다. 서로 다른 시스템이 의미에 대해 합의할 수 있도록 등록된 클레임 이름 집합이 표준화되어 있습니다. 발급자 클레임(iss)은 토큰을 누가 만들었는지를, 주체 클레임(sub)은 토큰이 누구 또는 무엇에 관한 것인지(흔히 사용자 ID)를 식별하며, 대상 클레임(aud)은 의도된 수신자를 가리킵니다. 이와 함께 역할이나 테넌트 같은 애플리케이션 고유의 사용자 정의 클레임도 흔히 보게 됩니다.
이 디코더는 등록된 클레임을 라벨이 붙은 사람이 읽기 쉬운 형태로 보여 주므로, 알쏭달쏭한 짧은 이름들을 일일이 외우고 있을 필요가 없습니다. 디버깅 중에 토큰을 눈으로 훑으며 그것이 알맞은 서비스에 맞는 알맞은 토큰인지 확인할 때는, 발급자와 주체, 대상이 풀어 적혀 있는 것만으로 충분한 경우가 많습니다.
시간 클레임: exp, iat, nbf
토큰의 수명을 좌우하는 클레임은 세 가지이며, 모두 초 단위로 측정되는 유닉스 타임스탬프입니다. 밀리초가 아니라는 점이, 밀리초 단위 시간에 익숙한 자바스크립트 개발자들이 1,000배만큼 어긋나는 버그를 자주 일으키는 지점입니다. 만료 클레임(exp)은 그 이후로 토큰을 반드시 거부해야 하는 시점이고, 발급 클레임(iat)은 토큰이 생성된 시각을 기록하며, 유효 시작 클레임(nbf)은 토큰이 유효해지는 가장 이른 순간을 표시합니다.
디코더는 이를 읽기 쉬운 날짜로 변환하고, 사용자 기기의 시계를 기준으로 토큰이 현재 유효한지, 아직 유효하지 않은지, 아니면 만료되었는지를 알려 줍니다. 마지막 항목은 특히 중요합니다. 컴퓨터의 시계가 틀려 있으면 유효 여부 판정이 잘못 나올 수 있고, 운영 환경에서는 서버 간 시계 오차가 방금 발급된 토큰이 아직 유효하지 않다며 거부되는 흔한 원인이 됩니다.
디코딩은 검증이 아니다
이것이 반드시 마음에 새겨야 할 가장 중요한 한 가지입니다. JWT는 누구나 디코딩할 수 있습니다. 그저 Base64URL일 뿐이기 때문입니다. 따라서 클레임을 읽는다고 해서 알 수 있는 것은 토큰이 무엇을 말하는지일 뿐, 토큰이 진짜인지가 아닙니다. 신뢰는 오직 키에 대해 서명을 검증할 때에만 생깁니다. 그래야 토큰이 시크릿이나 개인 키를 가진 측에서 발급되었고, 발급 이후 변조되지 않았음이 증명됩니다.
HMAC 토큰(HS256, HS384, HS512)이라면 이 도구는 헤더와 페이로드, 그리고 사용자가 입력한 시크릿으로 서명을 다시 계산해 토큰의 서명과 비교하고, 그 시크릿에 대한 진위를 확인해 줍니다. RS256, ES256 같은 비대칭 알고리즘은 발급자의 공개 키가 필요하므로 여기서는 디코딩만 되고 검증은 되지 않습니다. 무엇보다도 실제 인가 결정은 반드시 서버 측에서 서명을 검증해야 합니다. 클라이언트 코드에서 디코딩만으로 토큰의 클레임을 절대 믿어서는 안 됩니다.
페이로드는 비밀이 아니다
페이로드는 인코딩만 되어 있기 때문에, 그 안의 모든 클레임은 토큰을 손에 넣는 누구에게나 그대로 드러납니다. 브라우저든, 중간의 프록시든, 사용자 본인이든 마찬가지입니다. JWT는 민감하지 않은 신원 및 인가 데이터를 담기에는 더없이 좋은 곳이지만, 기밀에 해당하는 무언가를 담기에는 최악의 장소입니다. 인코딩이 보호해 주리라 생각하고 비밀번호나 API 시크릿, 신용카드 번호, 개인적인 사적 정보를 페이로드에 절대 넣지 마세요. 그렇게 보호되지 않습니다.
서명은 무결성을 보호하는 것이지 기밀성을 보호하는 것이 아닙니다. 변조는 막아 주지만 내용을 숨기는 일은 전혀 하지 못합니다. 페이로드를 읽을 수 없는, 진정으로 암호화된 토큰이 필요하다면 그것은 더 무거운 별개의 구성(JWE)입니다. 표준 JWT는 서명될 뿐 암호화되지는 않습니다. 비밀은 서버에 두고, 토큰에는 그것을 가리키는 불투명한 식별자만 담으세요.
토큰을 안전하게 디버깅하기
일상적인 작업에서 이 디코더는 인증 흐름을 디버깅할 때 빛을 발합니다. 주체 클레임에 알맞은 사용자가 들어 있는지 확인하고, 요청을 거부한 서비스와 대상이 일치하는지 점검하며, 스코프나 역할이 들어 있는지 검증하고, 만료 시각을 읽어 401이 그저 오래된 토큰 탓인지 살펴볼 수 있습니다. 정리된 헤더나 페이로드를 버그 리포트나 테스트 픽스처에 복사해 넣는 일은 클릭 한 번이면 됩니다.
모든 처리는 브라우저 안에서 로컬로 이루어지며, 입력한 토큰이나 시크릿은 업로드되거나 기록·저장되지 않으므로 실제 운영 환경의 토큰을 살펴봐도 안전합니다. 다만 토큰은 그 자체로 자격 증명이므로 그에 걸맞게 다루세요. 유효하고 만료되지 않은 토큰은 어떤 계정으로 들어갈 수 있는 살아 있는 열쇠입니다. 따라서 신뢰할 수 없는 도구에 함부로 붙여넣지 말고, 예시를 공유할 때는 만료되었거나 테스트용인 토큰을 쓰는 편이 좋습니다.
자주 묻는 질문
JSON 웹 토큰(JWT)이란 무엇인가요?
JWT를 디코딩하면 비밀번호나 시크릿이 노출되나요?
여기서 서명 검증은 어떻게 이루어지나요?
exp와 iat 클레임은 무슨 의미인가요?
내 토큰이 서버로 전송되나요?
관련 도구
이런 편리한 도구도 함께 사용해 보세요