logo
GeekFormat

JWT 도구

Encoded Token172 chars2026-07 업데이트
header
payload
signature
Valid JWTHS256
Secret38 chars
Header
{
  "alg": "HS256",
  "typ": "JWT"
}
Payload
{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "iat": 1516239022
}
Claims details4 items
sub· 주체1234567890
name· NameJohn Doe
admin· Admintrue
iat· 발급 시간15162390222018. 01. 18. 09:30:22
Header details2 items
algHS256HMAC(대칭)
typ· TypeJWT
All operations run locally in your browser; the Token and key are never sent to any server.

온라인 JWT 도구. JWT Token 디코딩, 검증 및 생성 지원. Header, Payload 및 서명 정보 확인. 인터페이스 인증 디버깅에 적합.

관련 추천

사용 사례

  • JWT 온라인 디코딩: OAuth 2.0 / OIDC 로그인 디버깅 중 Header 알고리즘과 Payload Claims 를 빠르게 확인합니다
  • JWT 서명 검증: Secret 또는 공개키로 서명을 검증해 401 원인이 서명 불일치, 만료, 알고리즘 불일치 중 무엇인지 가려냅니다
  • 연동 테스트용 JWT 생성: 백엔드에 임시 발급 코드를 부탁하지 않고 브라우저에서 테스트 키 페어로 JWT 를 발급합니다
  • PEM ↔ JWK 변환: OIDC IdP 가 JWK 를 제공했지만 서버는 PEM 을 요구하는 상황에서 OpenSSL 스크립트 없이 형식을 맞춰 봅니다
  • 401 Unauthorized 진단: 만료 시간, alg 와 Gateway 설정, 키 일치 여부, PEM 형식을 순서대로 확인합니다
  • RS256 과 PS256 비교: 같은 RSA 키 페어로 알고리즘을 바꿔 OIDC Provider, AWS SigV4 와의 차이를 확인합니다
  • JWT 내부 구조 학습: alg 를 바꾸거나 Payload 를 수정하거나 키를 교체했을 때 서명이 어떻게 깨지는지 바로 확인합니다

주요 기능

  • 디코딩·검증·생성을 한 화면에서 처리: Token 을 붙여 넣으면 Header/Payload/Signature 로 나누고, 알고리즘과 키를 바꿔 서명을 검증한 뒤 Claims 를 수정해 다시 서명할 수 있습니다
  • 13가지 알고리즘 지원: HS256/HS384/HS512, RS256/RS384/RS512, ES256/ES384/ES512, PS256/PS384/PS512, EdDSA 를 다루며 OAuth 2.0, OIDC, JWS, API Gateway, SSO 디버깅에 맞습니다
  • PEM 과 JWK 형식 지원: RSA, ECDSA, Ed25519 키를 PEM 문자열 또는 JWK JSON 으로 읽을 수 있고, OIDC 의 `/.well-known/jwks.json` 출력도 그대로 확인할 수 있습니다
  • HMAC Secret 입력 형식 선택: UTF-8 문자열, Hex 바이트, Base64/Base64URL Secret 을 전환할 수 있어 “겉보기엔 같은데 서명이 안 맞는” 문제를 빠르게 좁힐 수 있습니다
  • 브라우저에서 테스트용 키 페어 생성: RSA-2048, RSA-4096, P-256, P-384, Ed25519 키 페어를 만들고 PEM/JWK 두 형식으로 바로 확인합니다
  • Claims 의미 기반 표시: exp / iat / nbf 를 사람이 읽는 시간으로 바꾸고, 만료됨·아직 유효하지 않음·발급 시각 상태를 눈에 띄게 표시합니다. Header 의 alg / typ / kid 도 따로 확인할 수 있습니다
  • 100% 클라이언트 처리: 파싱, 검증, 서명은 브라우저의 Web Crypto API 로 실행되며 Token, 키, Payload 는 브라우저 밖으로 나가지 않습니다
  • 원클릭 복사: Header, Payload, Signature, 새로 만든 Token 을 각각 복사해 문서, 이슈, curl 명령에 바로 붙여 넣을 수 있습니다

이용 방법

  1. Token 붙여 넣기: JWT 문자열을 입력하면 Header, Payload, Signature 로 자동 분리되고 각각 JSON 으로 보기 좋게 정리됩니다
  2. 알고리즘 선택: HS256 / RS256 / ES256 / PS256 / EdDSA 등을 전환합니다. Header.alg 를 기준으로 추정하고 불일치가 있으면 표시합니다
  3. 키 가져오기: HMAC Secret, PEM 문자열, JWK JSON 을 붙여 넣습니다. 비대칭 알고리즘은 “키 페어 생성”으로 테스트 키를 바로 만들 수 있습니다
  4. 검증 또는 재서명: Decode 모드에서는 공개키로 서명을 검증하고, Encode 모드에서는 Claims 를 수정한 뒤 개인키로 서명해 새 Token 을 만듭니다

자주 묻는 질문

JWT 는 어떤 세 부분으로 구성되나요?

JWT 는 `Header.Payload.Signature` 형식입니다. 각 세그먼트는 Base64URL 로 인코딩됩니다. Header 는 알고리즘(예: HS256, RS256)과 typ 를 담고, Payload 는 sub, iat, exp, nbf, aud, iss 같은 Claims 를 담습니다. Signature 는 앞의 두 세그먼트에 대한 키 기반 서명이며, 내용 숨김이 아니라 변조 여부를 확인하기 위한 것입니다.

JWT 를 디코딩한 뒤 Payload 를 수정할 수 있나요?

볼 수도 있고 수정할 수도 있지만, 유효한 Token 을 마음대로 위조할 수는 없습니다. Header 나 Payload 를 한 글자라도 바꾸면 원래 Signature 는 무효가 되고 서버가 거부합니다. 수정한 Token 을 유효하게 만들려면 같은 알고리즘과 키로 다시 서명해야 합니다. 이 도구는 디코딩, 편집, 생성을 한 화면에서 처리해 테스트 Token 을 빠르게 만들 수 있게 합니다.

HS256, RS256, ES256, PS256, EdDSA 는 무엇이 다른가요?

HS256 은 HMAC + SHA-256 으로 같은 Secret 이 서명과 검증에 쓰이는 공통키 방식입니다. RS256 은 RSA 개인키로 서명하고 공개키로 검증하는 방식으로 OIDC 에서 흔합니다. PS256 은 RSA-PSS 를 쓰는 RS256 의 보안 개선 선택지입니다. ES256 은 P-256 타원곡선을 사용해 서명이 짧고, EdDSA(Ed25519)는 빠르고 결정적인 서명이 특징입니다.

JWT 가 계속 'Invalid Signature' 로 표시되는 이유는 무엇인가요?

가장 흔한 원인은 서버의 Secret 또는 공개키와 붙여 넣은 키가 다르거나, PEM 개행·빈 줄·끝 공백이 섞였거나, Base64 와 Base64URL 을 혼동했거나, Header 는 HS256 인데 RS256 으로 검증했거나, Secret 을 Hex/Base64 로 잘못 해석한 경우입니다. 먼저 키, 알고리즘, Secret 입력 형식을 고정하고 확인하세요.

같은 RSA 키로 RS256 과 PS256 을 서로 검증할 수 있나요?

**할 수 없습니다.** RS256 은 RSASSA-PKCS1-v1_5, PS256 은 RSA-PSS 로 패딩과 검증 로직이 다릅니다. 같은 RSA 키를 쓰더라도 RS256 으로 서명한 Token 은 PS256 으로 검증되지 않습니다. 서명 측과 검증 측의 알고리즘을 반드시 맞추고, RSA-PSS 에서는 saltLength 설정도 맞춰야 합니다.

alg: none 공격은 무엇이고 어떻게 막나요?

공격자가 Header 를 `{"alg":"none"}` 으로 바꾸고 서명 없는 Token 을 통과시키려는 고전적인 JWT 취약점입니다. RS256 을 HS256 으로 바꿔 공개키를 Secret 처럼 쓰게 하는 변형도 있습니다. 방어책은 분명합니다. 서버에서 `algorithms: ['RS256']` 처럼 허용 알고리즘을 고정하고, Token Header 가 검증 방식을 결정하게 두지 마세요.

PEM 과 JWK 는 어떻게 변환하나요? 어느 쪽이 더 흔한가요?

PEM 은 `-----BEGIN PUBLIC KEY-----` 로 감싼 Base64 문자열로 OpenSSL, Java, Go 같은 전통적인 서버 환경에서 흔합니다. JWK 는 `kty`, `n`, `e`, `kid`, `alg` 등을 담은 JSON 이며 OAuth 2.0 / OIDC 에서 표준적인 키 표현입니다. OIDC IdP 는 보통 `/.well-known/jwks.json` 으로 공개키를 JWK 로 제공합니다. 이 도구는 PEM 과 JWK 둘 다 읽을 수 있습니다.

브라우저만으로 JWT 서명을 검증할 수 있나요?

가능합니다. 브라우저 표준 Web Crypto API(`window.crypto.subtle`)는 HMAC, RSA, ECDSA, RSA-PSS, Ed25519 서명과 검증을 지원합니다. 이 도구는 프런트엔드에서 `crypto.subtle.importKey` 와 `crypto.subtle.verify` 를 사용하므로 Token 이나 키를 업로드하지 않고 검증할 수 있습니다. Web Crypto 는 HTTPS 또는 localhost 같은 안전한 컨텍스트에서 사용할 수 있습니다.

Token 이 서버로 전송되나요?

전송되지 않습니다. 파싱, 검증, 서명은 모두 브라우저 안의 Web Crypto API 로 실행됩니다. Token, Header, Payload, Signature, Secret, 개인키, 생성한 키 페어는 서버로 보내지지 않습니다. DevTools 의 Network 탭을 보면 Token 내용을 담은 외부 요청이 없는 것을 확인할 수 있습니다.

JWT 에 사용자 민감정보를 넣어도 안전한가요?

**안전하지 않습니다.** 일반 JWT Payload 는 평문이라 Token 을 가진 사람은 누구나 Base64URL 디코딩으로 내용을 읽을 수 있습니다. 비밀번호, 주민등록번호, 카드번호, API 키, access token, refresh token 등을 넣지 마세요. 비밀 유지가 필요하면 JWE 나 AES 같은 암호화 방식을 사용해야 합니다.

JWT 도구란?

JWT(JSON Web Token)는 RFC 7519 로 정의된 공개 표준입니다. HTTP 요청, OIDC 플로우, 마이크로서비스 호출 사이에서 “이 사용자가 누구인지”, “어떤 권한을 가졌는지” 같은 Claims 를 전달하는 데 쓰입니다. 일반적인 JWT 는 Base64URL 로 인코딩된 Header, Payload, Signature 세 부분을 `.` 으로 이어 붙인 문자열입니다. Header 에는 알고리즘과 타입, Payload 에는 Claims, Signature 에는 Header.Payload 에 대한 키 기반 서명이 들어갑니다.

**JWT 는 암호화가 아닙니다.** 가장 자주 생기는 오해가 이 부분입니다. 기본 JWT Payload 는 평문이라 누구나 Base64URL 디코딩으로 내용을 읽을 수 있습니다. JWT 가 제공하는 것은 내용 숨김이 아니라 “중간에 바뀌지 않았는지”를 확인하는 기능입니다. 비유하면 읽을 수 없는 티켓이 아니라 위조 방지 도장이 찍힌 티켓에 가깝습니다.

JWT 는 용도에 따라 여러 서명 알고리즘을 나눠 씁니다. HMAC 계열(HS256/HS384/HS512)은 같은 Secret 으로 서명과 검증을 하므로 단일 서비스나 신뢰된 내부 클러스터에 단순하고 빠릅니다. RSA 계열(RS256/RS384/RS512)은 개인키로 서명하고 공개키로 검증해 OIDC 에서 흔히 쓰입니다. RSA-PSS 계열(PS256/PS384/PS512)은 더 새로운 패딩을 쓰며, ECDSA 계열은 서명이 짧고, EdDSA(주로 Ed25519)는 빠르고 결정적인 서명이 특징입니다.

운영 환경에서 JWT 를 안전하게 쓰려면 기본 원칙을 지켜야 합니다. 비밀번호, 주민등록번호, 카드번호, API 키 같은 민감정보를 Payload 에 넣지 마세요. 서버는 Token Header 의 `alg` 를 믿지 말고 허용 알고리즘을 고정해야 합니다. HMAC Secret 은 짧은 문자열이 아니라 충분히 랜덤한 값이어야 하며, 서명뿐 아니라 `exp`, `nbf`, `iss`, `aud` 도 함께 검증해야 합니다. 이 도구는 Claims 상태를 강조해 서명 문제인지, 시간 또는 Claims 문제인지 빨리 구분하도록 돕습니다.

JWT 는 세션을 완전히 대체하는 기술이 아닙니다. 세션은 상태를 서버의 Redis 나 DB 에 두고, JWT 는 상태를 Token 안에 담습니다. 마이크로서비스, Stateless API, 모바일 앱, CORS 가 많은 구조에서는 JWT 가 편리하지만 즉시 강제 로그아웃이나 즉시 폐기가 중요한 업무 시스템에서는 세션이 더 다루기 쉬울 수 있습니다. 이 도구는 JWT 파싱, 서명 검증, Payload 편집, 재서명을 한 번에 확인하는 작업대입니다.

Code Examples

50 lines of Node.js: hand-written HS256 sign and verify

javascript

Distills JWT's core mechanism: encode Header and Payload in Base64URL, then HMAC-SHA256 the `header.payload` string. In production, use a library like jsonwebtoken or jose — this snippet exists to make signature failures debuggable.

const crypto = require('node:crypto')

function b64url(input) {
  return Buffer.from(input)
    .toString('base64')
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/, '')
}

function hmacSign(data, secret) {
  return b64url(crypto.createHmac('sha256', secret).update(data).digest())
}

function sign(payload, secret) {
  const header = b64url(JSON.stringify({ alg: 'HS256', typ: 'JWT' }))
  const body = b64url(JSON.stringify(payload))
  const signature = hmacSign(`${header}.${body}`, secret)
  return `${header}.${body}.${signature}`
}

function verify(token, secret) {
  const [h, p, s] = token.split('.')
  const expected = hmacSign(`${h}.${p}`, secret)
  const a = Buffer.from(s)
  const b = Buffer.from(expected)
  return a.length === b.length && crypto.timingSafeEqual(a, b)
}

const SECRET = 'my-super-secret-key'
const payload = { userId: 42, role: 'admin', exp: Math.floor(Date.now() / 1000) + 3600 }
const token = sign(payload, SECRET)

console.log(token)
console.log(verify(token, SECRET))       // true
console.log(verify(token, 'wrong-key'))  // false

Browser-side: Web Crypto API for HMAC signing

html

The core idea of this tool's front-end: use the browser's native crypto.subtle for HMAC, RSA, ECDSA, RSA-PSS and Ed25519 verification — no third-party library needed. Drop this into any HTML page to mint HS256 tokens.

<!doctype html>
<html>
  <body>
    <pre id="out"></pre>
    <script>
      const out = document.getElementById('out')

      const b64url = buf =>
        btoa(String.fromCharCode(...new Uint8Array(buf)))
          .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')

      const b64urlStr = str => b64url(new TextEncoder().encode(str))

      async function sign(payload, secret) {
        const header = b64urlStr(JSON.stringify({ alg: 'HS256', typ: 'JWT' }))
        const body = b64urlStr(JSON.stringify(payload))
        const data = new TextEncoder().encode(`${header}.${body}`)

        const key = await crypto.subtle.importKey(
          'raw',
          new TextEncoder().encode(secret),
          { name: 'HMAC', hash: 'SHA-256' },
          false,
          ['sign']
        )

        const sig = await crypto.subtle.sign('HMAC', key, data)
        return `${header}.${body}.${b64url(sig)}`
      }

      ;(async () => {
        const token = await sign({ user: 'alice', role: 'admin' }, 'browser-demo-secret')
        out.textContent = token
      })()
    </script>
  </body>
</html>

Node.js: verify RS256 with jose (the right way)

javascript

Use a mature library like jose, jsonwebtoken, or PyJWT in production — never roll your own. This snippet shows how jose verifies an RS256 token, prints the failure reason on error (alg mismatch, bad signature, expired, kid not found, etc).

import { jwtVerify, importSPKI } from 'jose'
import { readFile } from 'node:fs/promises'

const token = 'eyJhbGciOiJSUzI1NiIsImtpZCI6IjEifQ.payload.signature'
const publicKeyPem = await readFile('public.pem', 'utf8')

try {
  const { payload, protectedHeader } = await jwtVerify(
    token,
    await importSPKI(publicKeyPem, 'RS256'),
    {
      issuer: 'https://idp.example.com',
      audience: 'my-app',
      algorithms: ['RS256'],     // critical: algorithm whitelist blocks alg:none and HS256-substitution attacks
    }
  )
  console.log('alg =', protectedHeader.alg)
  console.log('sub  =', payload.sub)
} catch (err) {
  console.error('verify failed:', err.code, err.message)
  // common: ERR_JWT_EXPIRED / ERR_JWS_INVALID / ERR_JWS_SIGNATURE_VERIFICATION_FAILED
}

Python: parse a token and print its Claims with PyJWT

python

The most common way to debug JWT on the Python side. PyJWT's decode() validates exp / nbf / iat by default and returns the result as a plain dict.

import jwt

token = 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0In0.SflKxw'

# Parse (no signature check, just look at Header and Payload)
print(jwt.get_unverified_header(token))
# {'alg': 'HS256', 'typ': 'JWT'}

print(jwt.decode(token, options={'verify_signature': False}))
# {'sub': '1234'}

# Full verification
claims = jwt.decode(
    token,
    'my-super-secret-key',
    algorithms=['HS256'],
    audience='my-app',
    issuer='my-service',
)
print(claims['sub'])

Supported Video Formats

FormatMIMEBrowser supportWhen to use
HS256 / HS384 / HS512HMAC + SHA-256/384/512Universal공통키 방식입니다. 같은 Secret 으로 서명과 검증을 하므로 단순하고 빠르지만, Secret 은 충분히 랜덤해야 하며 최소 32바이트 이상을 권장합니다.
RS256 / RS384 / RS512RSASSA-PKCS1-v1_5 + SHA-2Web Crypto API가장 흔한 비대칭 서명 방식입니다. 개인키로 서명하고 공개키로 검증합니다. 많은 OIDC IdP, API Gateway, 기업 SSO 에서 기본값으로 쓰입니다.
PS256 / PS384 / PS512RSA-PSS + SHA-2Web Crypto APIRS256 보다 새로운 RSA-PSS 기반 방식입니다. AWS SigV4, AWS Cognito, 최신 OIDC Provider 에서 쓰이는 경우가 있으며, saltLength 설정을 명시적으로 맞춰야 합니다.
ES256 / ES384 / ES512ECDSA + P-256/P-384/P-521Web Crypto API타원곡선 서명입니다. 서명이 짧아 JWT 전체 크기를 줄일 수 있고 성능도 좋습니다. Apple Sign in with Apple 에서는 ES256 이 기본적으로 쓰입니다.
EdDSA (Ed25519)Ed25519 / Ed448Web Crypto API차세대 고성능 서명 알고리즘입니다. 같은 메시지와 같은 키는 항상 같은 서명을 만들며 nonce 재사용 위험이 없습니다. OAuth 2.1 이후의 새 설계에서도 선호되는 방향입니다.

Output Example

A real MP3 file encoded to a Data URI — copy-ready:

Header (Base64URL):  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Payload(Base64URL):  eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbmUgRG9lIiwiaWF0IjoxNzE2MjM5MDIyfQ
Signature:           kZJfaYjK3iCkVFL5EL9zGRZ5SmD8_x2h6B5c7pVFfVGo

Header 디코딩:
  {
    "alg": "HS256",
    "typ": "JWT"
  }

Payload 디코딩:
  {
    "sub": "1234567890",
    "name": "Jane Doe",
    "iat": 1716239022        // 2024-05-20 14:23:42 UTC
  }

Privacy & Security

이 JWT 작업대는 브라우저 표준 Web Crypto API 를 사용해 100% 브라우저 안에서 동작합니다. 붙여 넣은 Token, Header, Payload, Signature, HMAC Secret, RSA/ECDSA 개인키, 생성한 키 페어, 모든 서명/검증 계산은 사용자의 기기 안에 머물며 서버로 전송되지 않습니다. 로그로 남기거나 분석하거나 캐시하지도 않습니다. 페이지가 한 번 로드된 뒤에는 오프라인에서도 사용할 수 있습니다. 다만 장기간 유효한 운영 Token 이나 운영 개인키를 아무 온라인 도구에 붙여 넣지 않는다는 기본 원칙은 지켜 주세요.

Authoritative References

Troubleshooting

Invalid Signature: 서명이 유효하지 않음

Token 과 검증 키가 서로 맞지 않습니다. 흔한 원인은 서버 키와 붙여 넣은 키가 다르거나, 끝 공백·개행 같은 보이지 않는 문자가 섞였거나, Base64 와 Base64URL 을 혼동했거나, Header 는 HS256 인데 RS256 으로 검증하는 경우입니다. 먼저 키가 바이트 단위로 같은지 확인하세요. PEM 끝 개행, HMAC Secret 뒤 공백, JWK `k` 값의 잘못된 URL 디코딩을 확인합니다. 그다음 Header.alg 와 실제 선택한 알고리즘이 맞는지, Secret 입력 형식이 UTF-8 / Hex / Base64 중 무엇인지 고정해서 다시 검증합니다.

HTTP 401 Unauthorized: Token 만료 또는 iat 미래 시각

서명 검증은 통과했지만 `exp` 가 과거이거나, `nbf` 가 아직 미래이거나, `iat` 가 서버 현재 시각보다 미래일 수 있습니다. 로컬 환경, 컨테이너, CI 에서는 시계 차이도 자주 원인이 됩니다. `aud` 가 맞지 않아 다른 앱용 Token 을 현재 서버가 검증하는 경우도 있습니다. 이 도구의 Claims 강조 표시로 exp / nbf / iat 상태를 확인하세요. exp 가 빨간색이면 재발급, nbf 가 빨간색이면 유효 시작 시각, iat 가 미래라면 서버와 클라이언트의 시간 동기화를 점검합니다. aud 가 다르면 서버의 audience 설정을 확인합니다.

PEM 또는 JWK 가져오기 오류

PEM 에 불필요한 빈 줄이 있거나 `-----BEGIN PUBLIC KEY-----` 같은 헤더/푸터가 빠졌을 수 있습니다. JWK 에 `kty` / `n` / `e` / `kid` 같은 필수 필드가 없거나, JWK `k` 값이 Base64URL 형식이 아니거나, 개인키/공개키 종류를 잘못 넣은 경우도 있습니다. 표준 PKIX PEM 으로 다시 내보내거나 OIDC Discovery 의 `/.well-known/jwks.json` 출력 원본을 그대로 사용하세요. 복사 과정에서 개행, 따옴표, 이스케이프가 깨지지 않았는지도 확인합니다.

RS256 과 PS256 의 언어 간 서명 실패

RS256 은 RSASSA-PKCS1-v1_5, PS256 은 RSA-PSS 를 사용합니다. 같은 RSA 키라도 서로 교차 검증할 수 없습니다. RS256 으로 서명한 Token 은 PS256 검증에 실패하고 반대도 마찬가지입니다. 서명하는 쪽과 검증하는 쪽이 같은 알고리즘을 쓰는지 확인하세요. AWS SigV4 는 PS256, 많은 OIDC IdP 는 RS256 을 쓰는 경우가 많습니다. RSA-PSS 는 `saltLength` 설정도 중요하므로 Node, Go, OpenSSL 등의 구현 설정을 맞춰야 합니다.

alg: none 공격과 HS256 키 대체 공격

서버가 Token Header 의 alg 값만 보고 검증 방식을 정하면, 공격자가 `alg: none` 으로 바꿔 서명 없는 Token 을 통과시키거나 RS256 Token 을 HS256 으로 바꿔 공개키를 Secret 처럼 쓰게 만들 수 있습니다. 서버에서는 반드시 `algorithms: ['RS256']` 처럼 허용 알고리즘을 고정하고, Token 이 검증 방식을 정하게 두면 안 됩니다. 이 도구는 Header.alg 와 실제 선택한 알고리즘을 따로 보여 주고 불일치를 확인할 수 있게 합니다.