툴박스 가이드는 W3C·MDN·국제 표준 문서(RFC/ISO)와 한국인터넷진흥원(KISA) 등 공신력 있는 기관의 공개 자료를 기반으로 작성·검토합니다.편집 방침 보기
API를 호출했더니 응답은 401 Unauthorized인데, 요청 헤더에는 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEwMjQi... 같은 의미를 알 수 없는 긴 문자열만 들어 있다. 이 문자열이 바로 JWT(JSON Web Token) 다. 로그인 인증의 사실상 표준(RFC 7519)으로 자리 잡았지만, 처음 보면 "이걸 어떻게 까서 봐야 하나" 막막하다. 이 글은 JWT를 직접 손으로 뜯어보고 검증 원리까지 이해하는 과정을 3단계로 정리한다.
JWT는 어떻게 생겼나
JWT는 점(.) 두 개로 구분된 세 부분으로 이루어진다. 한 덩어리처럼 보이지만 사실은 헤더.페이로드.서명 구조다.
| 부분 | 이름 | 담는 내용 | 형태 |
|---|---|---|---|
| 1 | 헤더(Header) | 토큰 타입과 서명 알고리즘 | Base64url 인코딩 |
| 2 | 페이로드(Payload) | 사용자 ID·만료 시각 등 클레임 | Base64url 인코딩 |
| 3 | 서명(Signature) | 위·변조 검증용 해시값 | 알고리즘으로 계산 |
핵심은 앞 두 부분이 암호화가 아니라 단순 인코딩이라는 점이다. 즉 키가 없어도 누구나 내용을 읽을 수 있다. 이 사실 하나만 알아도 JWT를 다룰 때 절반은 이해한 셈이다.
1단계: 점(.)으로 세 토막 내기
먼저 토큰을 . 기준으로 분리한다. 예를 들어 아래 토큰이라면
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEwMjQiLCJpYXQiOjE3MTgwMDAwMDB9.dQw4w9WgXcQ
- 첫 토막
eyJhbGci...J9→ 헤더 - 둘째 토막
eyJzdWIi...MDB9→ 페이로드 - 셋째 토막
dQw4w9WgXcQ→ 서명
세 토막이 아니라면(점이 1개거나 3개 이상) 그 시점에서 이미 정상 JWT가 아니다. 잘린 토큰이거나 다른 형식을 의심해야 한다.
2단계: 헤더와 페이로드 Base64url 디코딩하기
앞 두 토막은 Base64url(일반 Base64에서 +/=을 URL 안전 문자로 바꾼 변형)이다. Base64 인코딩·디코딩 도구에 각 토막을 붙여 넣으면 바로 JSON이 나온다. 위 예시를 디코딩하면 헤더는 {"alg":"HS256","typ":"JWT"}, 페이로드는 {"sub":"user_1024","iat":1718000000}이 된다.
페이로드에 자주 등장하는 표준 클레임은 다음과 같다.
| 클레임 | 의미 | 예시 값 |
|---|---|---|
iss | 발급자(issuer) | "auth.example.com" |
sub | 토큰 주체(사용자 식별자) | "user_1024" |
iat | 발급 시각(Unix 타임스탬프) | 1718000000 |
exp | 만료 시각(Unix 타임스탬프) | 1718003600 |
nbf | 이 시각 이후부터 유효 | 1718000000 |
iat·exp는 사람이 읽기 어려운 Unix 초 단위라서, Unix 타임스탬프 변환 도구로 날짜·시각으로 바꿔 보면 토큰이 언제 발급됐고 언제 만료되는지 한눈에 들어온다.
3단계: 서명이 검증하는 것
서명은 "헤더 + 페이로드"를 비밀키로 해시한 값이다. 누군가 페이로드의 sub를 다른 사용자 ID로 바꿔치기하면 서명 계산값이 달라지므로, 서버는 즉시 위조를 잡아낸다. 서명 방식은 헤더의 alg에 따라 갈린다.
| 알고리즘 | 방식 | 키 구조 | 주로 쓰는 곳 |
|---|---|---|---|
| HS256 | 대칭키(HMAC-SHA256) | 비밀키 하나로 서명·검증 | 단일 서버 내부 인증 |
| RS256 | 비대칭키(RSA-SHA256) | 개인키로 서명, 공개키로 검증 | 외부·분산 서비스 검증 |
즉 서명은 "내용을 숨기는 장치"가 아니라 "내용이 바뀌지 않았음을 보증하는 장치" 다. 페이로드 자체는 2단계처럼 누구나 읽을 수 있다는 점을 다시 기억하자.
실무에서 JWT 다룰 때 주의점
- 민감정보 금지: 비밀번호, 주민등록번호, 카드번호 등을 페이로드에 넣지 않는다. 인코딩일 뿐이라 그대로 노출된다.
- 만료(exp)는 짧게: 액세스 토큰은 수십 분 단위로 짧게 두고, 갱신은 별도의 리프레시 토큰으로 처리한다.
- 비밀키는 코드 밖으로: 서명 비밀키는
.env등 환경변수로 관리하고 깃 저장소에 커밋하지 않는다. alg: none공격 주의: 알고리즘을none으로 강제해 서명 검증을 우회하는 고전적 공격이 있으니, 서버는 허용 알고리즘을 화이트리스트로 고정해야 한다.
로그인 토큰처럼 계정과 결제 정보 보안이 신경 쓰인다면 안전한 온라인 쇼핑 체크포인트도 함께 보면 좋다. 더 많은 개발 도구 활용법은 kimgoon 개발 도구 가이드에서 찾아볼 수 있다.
자주 묻는 질문
JWT 안의 내용을 마음대로 바꿔도 통과하나요? 아니다. 페이로드를 바꾸면 서명 해시값이 달라져 서버 검증에서 거부된다. 다만 "읽는 것" 자체는 키 없이도 누구나 가능하다.
그럼 JWT는 암호화된 건가요? 기본 JWT(JWS)는 암호화가 아니라 서명이다. 내용 숨김이 목적이라면 별도의 암호화 규격인 JWE를 써야 한다.
토큰이 만료되면 매번 다시 로그인하나요? 보통은 짧은 액세스 토큰이 만료되면, 따로 발급받은 리프레시 토큰으로 새 액세스 토큰을 받아 사용자 재로그인 없이 이어 간다.
로그아웃하면 JWT가 바로 무효화되나요? 표준 JWT는 서버에 상태를 저장하지 않아 자동 무효화가 안 된다. 그래서 만료 시간을 짧게 두거나, 무효 토큰 블랙리스트를 별도로 운영한다.
관련 가이드
참고한 표준·공식 자료
본 글은 다음 표준·문서의 공개 자료를 바탕으로 정리·검토되었습니다. 최신 사양은 각 표준 문서를 함께 확인해 주세요.
- MDN Web Docs ↗웹 표준·HTML/CSS/JS 공식 문서
- W3C ↗웹 국제 표준 권고안
- IETF RFC Editor ↗인터넷 프로토콜·인코딩 표준 원문
- 한국인터넷진흥원(KISA) ↗보안·암호·개인정보 가이드
잘못된 정보나 갱신이 필요한 부분을 발견하셨다면 contact@kimgoon.kr로 알려주세요. 툴박스 편집 방침을 함께 참고하실 수 있습니다.








