JWT
2 tools
웹 보안 기초
Web security is the practice of protecting web applications and APIs from unauthorized access, data breaches, and attacks. Modern applications use authentication (proving who you are), authorization (proving what you can do), and cryptography to enforce security boundaries.
JSON Web Tokens (JWT) are the dominant stateless authentication mechanism in modern web development. Understanding how JWTs work — including their structure, signing algorithms, and vulnerabilities — is essential for building secure APIs and applications.
JSON Web Tokens (JWT)
A JWT is a compact, URL-safe way to represent claims between two parties. It consists of three Base64url-encoded parts separated by dots. JWTs can be verified without database lookups because the signature covers the entire token.
The Three Parts of a JWT
Contains metadata about the token: the signing algorithm (alg) and token type (typ). Always Base64url-encoded JSON. The algorithm choice here affects the security of the entire token.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9{
"alg": "HS256",
"typ": "JWT"
}Contains the claims: statements about the user and additional metadata. Also Base64url-encoded JSON. Anyone can decode this — payload data is NOT encrypted, only signed.
eyJzdWIiOiJ1c2VyXzEyMyIsInJvbGUiOiJhZG1pbiIsImV4cCI6MTcxNzIwMDAwMH0{
"sub": "user_123",
"role": "admin",
"exp": 1717200000
}A cryptographic signature over the encoded header and payload. Verifying this signature ensures the token was not tampered with. The secret key (HMAC) or private key (RSA/ECDSA) is never included in the token.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cHMACSHA256( base64url(header) + "." + base64url(payload), secret )
Standard JWT Claims
The JWT specification defines standard claim names. Using them ensures interoperability between different JWT libraries and services:
| 클레임 | 이름 | 설명 |
|---|---|---|
| iss | Issuer | Identifies the principal that issued the token (e.g., your auth server URL) |
| sub | Subject | Identifies the principal that is the subject of the token (e.g., user ID) |
| aud | Audience | Identifies the recipients that the token is intended for (e.g., your API URL) |
| exp | Expiration | Unix timestamp after which the token must not be accepted for processing |
| nbf | Not Before | Unix timestamp before which the token must not be accepted for processing |
| iat | Issued At | Unix timestamp at which the token was issued — used to determine age |
| jti | JWT ID | Unique identifier for the token, used to prevent token replay attacks |
서명 알고리즘
The signing algorithm is declared in the JWT header. Choosing the right algorithm for your use case is critical for security:
HS256 / HS384 / HS512대칭 (HMAC)Uses a shared secret key for both signing and verification. Simple to implement but requires all verifiers to know the secret.
RS256 / RS384 / RS512비대칭 (RSA)Uses a private key to sign and a public key to verify. The private key never leaves the auth server.
ES256 / ES384 / ES512비대칭 (ECDSA)Like RSA but with smaller keys and faster signing. Provides equivalent security with better performance.
"alg": "none"서명 없음 — 위험No signature at all. A token with alg:none has no integrity guarantee and can be forged by anyone.
인증 흐름
- 1.User submits username and password to the login endpoint
- 2.Server validates credentials against the user database
- 3.Server signs a JWT with user claims and expiration
- 4.Client stores JWT (localStorage, cookie, or memory)
- 5.Client sends JWT in Authorization: Bearer header for subsequent requests
- 1.Client redirects user to authorization server with code challenge
- 2.User authenticates and authorizes the client application
- 3.Auth server redirects back with a one-time authorization code
- 4.Client exchanges code + verifier for access and refresh tokens
- 5.Client uses access token for API calls; refresh token for renewal
일반적인 JWT 취약점
JWTs are secure when implemented correctly. These are the most common implementation mistakes that lead to security vulnerabilities:
Some libraries accept tokens with alg:none (no signature). An attacker can modify the payload and set alg to none to forge any JWT. Always explicitly specify and validate the allowed algorithm.
If a library is expected to verify RS256 but accepts HS256, an attacker can sign a token using the public key as the HMAC secret. The library verifies it successfully. Always pin the expected algorithm.
A JWT without an exp claim, or code that does not check exp, allows tokens to be used indefinitely after a user logs out or is banned. Always set short expiration times and validate the exp claim.
JWT payloads are Base64-encoded, not encrypted. Anyone who intercepts a JWT can decode and read the payload. Never store passwords, credit card numbers, or other secrets in JWT claims.
HMAC-signed JWTs with short or predictable secrets can be brute-forced offline. An attacker who obtains a JWT can try billions of keys per second. Use cryptographically random secrets of at least 256 bits.
Accepting JWTs without verifying the signature trusts the payload completely. This is a critical bug that allows any user to craft arbitrary claims. Always verify the signature before trusting any claim.
자주 묻는 질문
Standard JWTs (JWS — JSON Web Signature) are signed but NOT encrypted. The payload is Base64url-encoded, which is trivially reversible. Anyone who obtains a JWT can read its contents. JWE (JSON Web Encryption) provides encryption, but is much less common.
Access tokens should be short-lived: 5–60 minutes is typical. Long-lived tokens are dangerous because they cannot be revoked without a token blocklist. Use refresh tokens (longer-lived, stored securely) to obtain new access tokens.
HttpOnly cookies are the most secure option — they are inaccessible to JavaScript, preventing XSS theft. localStorage is vulnerable to XSS attacks but avoids CSRF. Memory (JavaScript variable) is safest but does not survive page refresh. There is no perfect option.
Not without server-side state. The stateless nature of JWTs means the server cannot invalidate them. Solutions: short expiration times, a token blocklist (Redis), rotating refresh tokens, or switching to opaque session tokens for sensitive operations.
Session cookies store a random session ID; the server looks up session data. JWTs are self-contained — the server validates the signature without a database lookup. JWTs scale better across multiple servers but cannot be revoked without extra infrastructure.
The minimum: sub (user ID), exp (expiration), and iat (issued at). Add iss (issuer) for multi-service setups. Keep payloads small — JWTs are sent with every request. Do not include sensitive data or large profile objects.
RS256 (asymmetric) is better for most production systems because only the auth server needs the private key. Multiple services can verify tokens using the public key without sharing a secret. HS256 is simpler but requires all verifiers to know the shared secret.
PKCE (Proof Key for Code Exchange) is an extension to the OAuth2 authorization code flow that prevents authorization code interception attacks. It is required for public clients (SPAs, mobile apps) that cannot securely store a client secret.