본문으로 바로가기
JWT 디코더
샘플 JWT 구조·만료 시각 확인. 서명 검증 없음.
블로그

JWT 토큰 만료와 payload 확인하는 법 (2026)

401 원인을 살펴볼 때 샘플 JWT의 payload와 exp를 읽는 법, 디코드와 검증의 차이, 실제 액세스 토큰 취급 주의사항을 정리합니다.

401 Unauthorized 화면을 띄운 노트북과 '401, 만료일까 권한일까'라고 적힌 메모가 놓인 따뜻한 책상 사진.

안내 보완 · 2026년 10월 14일: 1시간 계산 예시와 내장 샘플을 구분하고, UTC·한국시간 및 입력 시각 기준을 덧붙였습니다.

서버가 401 Unauthorized를 던집니다. 토큰이 만료된 걸까요, 권한이 모자란 걸까요. 샘플 토큰의 exp는 만료 여부를 살펴볼 단서지만, 401의 원인을 혼자서 증명하지는 못합니다. 실제 인증정보를 온라인 도구에 붙여넣지 않고 구조를 이해하는 법부터 정리합니다.

서명형 JWT의 payload는 암호화가 아니라 인코딩이다

이 글과 도구가 다루는 일반적인 서명형 JWT는 점(.)으로 이어진 세 조각입니다. header.payload.signature 순서이며, header와 payload는 base64url로 인코딩돼 있습니다. 암호화된 JWT는 형식이 다를 수 있습니다.

흔한 오해가 여기서 생깁니다. base64url은 암호화가 아니라 단순 인코딩이라, 비밀키 없이도 누구나 되돌려 읽을 수 있습니다. 즉 payload에 담긴 사용자 ID나 권한은 토큰을 가진 사람 누구에게나 보입니다. 비밀번호나 민감 정보를 payload에 넣으면 안 되는 이유입니다.

payload에 들어가는 클레임 읽기

payload 안의 각 항목을 클레임(claim)이라고 부릅니다. RFC 7519가 표준 클레임을 정의해 둬서, 이름만 알면 의미가 바로 읽힙니다.

클레임의미
iss발급자 (issuer)
sub토큰 주체 (subject, 보통 사용자 ID)
aud대상 (audience)
exp만료 시각 (expiration)
iat발급 시각 (issued at)
nbf활성 시작 시각 (not before)
jti토큰 고유 ID

exp, iat, nbf 세 개가 시간 클레임이고, 디버깅에서 가장 자주 보게 됩니다.

만료 확인: exp는 Unix epoch라 그냥 읽기 어렵다

exp가 만료 시각이긴 한데, 값이 1700003600 같은 숫자입니다. 사람이 읽으라고 만든 게 아니라 Unix epoch, 즉 1970년부터의 경과 초입니다.

단위는 밀리초가 아니라 초입니다(RFC 7519의 NumericDate). JavaScript의 new Date()에 넣을 때는 1,000을 곱해야 합니다. 아래 1시간 예시는 내장 샘플과 별개인 산술 예시입니다.

  • iat: 1700000000 → 2023-11-14T22:13:20Z
  • exp: 1700003600 → 2023-11-14T23:13:20Z
  • 차이는 3,600초입니다. 서명이나 실제 사용 가능 기간을 입증하지는 않습니다.

실제 샘플로 UTC와 한국시간 대조하기

  1. 한국어 JWT 디코더를 열어 샘플을 누릅니다. 실제 계정의 토큰이나 붙여넣기는 필요 없습니다.
  2. Payload의 시간값은 iat: 1718500000, exp: 1900000000입니다. 위의 1시간 예시와 다릅니다.
  3. 표시된 UTC 시각과 다음 한국시간을 대조합니다. 도구는 UTC를 표시하며, 한국시간은 이 글에서 따로 환산한 값입니다.
항목도구의 UTC한국시간 (UTC+9)
iat2024-06-16 01:06:402024-06-16 10:06:40
exp2030-03-17 17:46:402030-03-18 02:46:40

도구의 ISO 문자열 끝에 붙는 .000Z에서 Z는 UTC입니다. 만료 시각은 한국시간으로 다음 날이므로, 서버 로그와 비교할 때 날짜만 보고 불일치라고 판단하지 마세요. 샘플의 두 값 차이는 181,500,000초입니다. 공개 시연 값이지 권장 토큰 수명이 아닙니다.

다음 코드는 공개 샘플의 숫자만 계산합니다. 실제 토큰을 입력하거나 서버에 보내지 않습니다.

const expSeconds = 1900000000;
const utc = new Date(expSeconds * 1000).toISOString();
const kst = new Intl.DateTimeFormat('ko-KR', {
  timeZone: 'Asia/Seoul', dateStyle: 'short', timeStyle: 'medium',
  hourCycle: 'h23'
}).format(new Date(expSeconds * 1000));
console.log({ utc, kst });

utc는 2030-03-17T17:46:40.000Z이고, kst는 2030년 3월 18일 02:46:40을 나타냅니다. 구두점·공백은 실행 환경에 따라 다를 수 있습니다. 1,000을 곱하지 않은 new Date(1900000000)은 1970년 날짜가 되므로 같은 값이 아닙니다.

배지는 실시간 카운트다운이 아니다

결과의 입력 시각 기준을 확인하세요. 이 도구는 입력이 바뀔 때 기기의 시각으로 비교합니다. 같은 토큰을 그대로 둔다고 만료 순간에 배지가 자동으로 갱신되는 것은 아닙니다. 공개 샘플을 새로 비교하려면 비우기 → 샘플을 누르고 기준 시각이 바뀌었는지 봅니다.

2026년 10월 14일 확인 당시에는 표기된 만료 시각 전이 나왔습니다. 만료 시각에 도달하면 비교 결과가 달라져야 하지만, 어느 쪽도 미검증 안내를 없애지 않습니다. 기기 시계와 서버의 검증 시계·허용 오차가 다를 수도 있습니다.

샘플에는 iss, aud, nbf가 없습니다. 따라서 발급자·대상·활성 시작 조건을 통과했다는 뜻이 아닙니다. 실제 401 원인은 서버의 검증 결과와 조직에서 승인한 로컬 절차로 확인하고, 이 공개 시연 토큰을 API에 보내 시험하지 마세요.

디코드는 검증이 아니다

가장 중요한 구분입니다. 토큰을 디코드해 내용을 읽는 것과, 그 토큰이 진짜인지 검증하는 것은 다릅니다.

세 번째 조각인 서명(signature)은 발급자가 서명키로 만든 값입니다. 위조되지 않았는지 확인하려면 발급자의 알고리즘과 신뢰할 수 있는 비밀키 또는 공개키로 서명을 검증해야 합니다(RFC 7515). 이 디코더는 키를 받지도 보관하지도 않으므로 검증을 하지 않습니다. 따라서 디코드해서 보이는 payload는 “서버가 서명을 검증하기 전까지는 신뢰할 수 없는 값”으로 다뤄야 합니다. payload의 role이 admin이라고 적혀 있어도, 검증 없이 그 말을 믿으면 안 됩니다.

그 운영 토큰, 어디에 붙여넣고 있나요

401을 디버깅하려고 운영 환경의 액세스 토큰을 온라인 디코더에 붙여넣지 마세요. bearer 토큰은 가진 사람이 사용할 수 있는 인증정보이므로 노출 자체가 위험합니다(RFC 6750).

PiPi Worlds JWT 디코더의 디코드 처리는 브라우저에서 실행되지만, 실제 운영 토큰의 안전을 보증하는 기능은 아닙니다. 내장 샘플이나 시험용 토큰으로 구조를 살펴보고, 운영 장애는 조직에서 승인한 로컬 디버깅 절차와 서버 검증 결과로 확인하세요. 시험용 payload를 더 보기 좋게 펼치려면 JSON 포맷터를, base64url 인코딩을 살펴보려면 Base64 도구를 사용할 수 있습니다.

자주 묻는 질문

JWT 디코더는 토큰이 유효한지도 검사하나요?
아니요. 디코더는 입력 시각을 기준으로 `exp` 클레임과 비교한 결과만 표시하고, 암호 서명 검증은 하지 않습니다. 토큰이 위조되지 않았는지 확인하려면 백엔드의 비밀키나 공개키로 서명을 검증해야 합니다. 디코드와 검증은 다른 단계입니다.
토큰 만료 시각은 어떻게 읽나요?
payload에 `exp`가 있다면 그 값은 Unix epoch(초)로 적힌 만료 시각입니다. 디코더가 이를 ISO 형식으로 환산합니다. `iat`도 있다면 `exp - iat`는 토큰이 주장하는 기간일 뿐, 서명이나 실제 사용 가능성을 증명하지 않습니다.
payload는 암호화되어 있나요?
이 글의 일반적인 서명형 JWT에서는 header와 payload가 base64url로 인코딩되어 누구나 읽을 수 있습니다. 암호화가 아니므로 비밀번호 같은 민감 정보를 payload에 넣으면 안 됩니다. 암호화된 JWT는 형식이 다릅니다.
401 오류가 토큰 만료 때문인지 어떻게 아나요?
시험용 토큰의 `exp`를 입력 시각과 비교해 볼 수 있습니다. 입력을 그대로 두면 배지가 실시간으로 갱신되지는 않습니다. 다만 이 도구의 만료 표시는 서명·발급자·대상·권한을 검증하지 않으므로 401 원인을 확정하지 못합니다. 실제 운영 장애는 서버 로그와 발급처의 검증 결과로 확인하세요.
실제 운영 토큰을 디코더에 붙여넣어도 되나요?
권장하지 않습니다. 유효한 bearer 토큰은 인증정보이므로 내장 샘플이나 시험용 토큰을 사용하세요. PiPi Worlds의 디코드 처리는 브라우저에서 실행되지만, 그 사실만으로 실제 토큰을 웹사이트에 붙여넣는 행위가 안전하다고 보장할 수 없습니다. 노출됐다면 발급처의 폐기·교체 절차를 따르세요.

출처

검토 기록: Codex AI의 편집·코드 검토(사람 전문가의 감수 아님)

이번 검토 범위 — 이번 날짜는 공개 샘플의 시간값·UTC/한국시간 환산·입력 시각 기준 안내 검토에 해당합니다. 서명 구현 전체·표지 이미지에 대한 새 감사는 아닙니다.

확인 내역과 한계 펼쳐 보기

2026-10-14 한국어 운영 도구의 샘플 버튼으로 payload·UTC 날짜·미검증 및 입력 시각 기준 표시를 확인했습니다. RFC 7519·6750을 다시 읽고 초·UTC·한국시간을 독립 검산합니다. 이번 검토는 시간 예시 범위이며 전체 보안·이미지 검수나 사람 전문가 감수가 아닙니다. 다시 읽지 않은 RFC 7515의 접근일은 유지합니다.

이 글에서 더한 것 — 내장 샘플의 실제 시간값을 UTC와 한국시간으로 대조하고, 별도의 1시간 산술 예시와 구분합니다. 초·밀리초 혼동 및 입력 시각 기준 배지의 한계를 공개 값으로 재현합니다.

검토 기록은 기재된 확인 내역이며, 독립적인 정확성 보증은 아닙니다.

도구로 돌아가기 →