최근 수정 시각 : 2026-09-14 20:31:15

JSON Web Token

JSON 기반 보안 표준 · JOSE
핵심형식 JSON Web Token(JWT) · JSON Web Signature(JWS) · JSON Web Encryption(JWK)
키와 알고리즘JSON Web Key(JWK) · JSON Web Algorithms(JWA)
연관 표준OAuth· OpenID Connect · Bearer Token
기반 형식JSON · Base64url · UTF-8
JSON Web Token
JWT
<nopad> 파일:JWT.io logo.svg
정식 명칭JSON Web Token
약어JWT
종류클레임 기반 보안 토큰 형식
표준RFC 7519
표준 상태제안 표준(Proposed Standard)
발행2015년 5월
표준화 기관IETF OAuth Working Group
미디어 타입application/jwt
주요 형식JWS Compact Serialization
JWE Compact Serialization
RFC Editor · IETF datatracker

JSON Web Token(JWT)은 여러 시스템 사이에서 전달할 정보를 JSON 형태의 클레임으로 묶고, 서명이나 암호화를 통해 그 정보를 보호할 수 있게 만든 토큰 형식이다.

웹 인증에서는 인증 서버가 사용자와 권한 토큰의 대상, 만료 시간 등을 담아 JWT를 발급하고, API 서버가 서명과 클레임을 검증한 뒤 요청을 허용하거나 거부한다. JWT 자체는 로그인 절차나 OAuth를 대신하는 프로토콜이 아니며, 어디에 어떻게 사용할지는 상위 프로토콜과 애플리케이션이 정한다.

1. 개요
1.1. 처음 읽기 전에1.2. 세션 방식과의 차이1.3. 주로 쓰이는 경우
2. 구조
2.1. JWS 기반 JWT
2.1.1. Protected Header2.1.2. Payload2.1.3. Signature
2.2. JWE 기반 JWT2.3. 중첩 JWT2.4. JWE가 필요한 경우2.5. Base64url
3. 주요 클레임4. 발급과 검증
4.1. 발급4.2. 검증4.3. JWK Set과 키 교체
5. 알고리즘과 키6. OAuth 2.0·OpenID Connect와의 관계7. 장점
7.1. 중앙 조회를 줄일 수 있음7.2. 마이크로서비스와 수평 확장에 유리할 수 있음7.3. 언어와 플랫폼에 덜 종속됨
8. 단점과 운영 대책
8.1. 즉시 폐기가 어려움8.2. 권한 정보가 오래될 수 있음8.3. 키 관리가 필요함8.4. 보안
9. 구현체10. JWT를 사용할지 결정할 때11. 관련 문서12. 외부 링크

JWT JWS JWE
클레임을 담아 전달하는 토큰 형식 서명 또는 MAC으로 변조 여부를 확인하는 형식 내용을 암호화하고 무결성도 확인하는 형식
JWS 또는 JWE 구조 안에 Claims Set을 담는다. Compact 형식은 3부분이다. Compact 형식은 5부분이다.
핵심
JWT의 장점은 여러 API가 발급 서버나 중앙 세션 저장소에 매번 질의하지 않고도 토큰을 검증하도록 설계할 수 있다는 점이다. 반대로 즉시 로그아웃, 강제 폐기, 실시간 권한 변경이 필요하면 Redis나 데이터베이스 같은 상태 저장소를 함께 사용하기도 한다.

1. 개요


JWT는 전달한 정보를 이름과 값의 쌍인 클레임으로 표현한다. 다음은 발급자, 사용자, 대상 API와 만료 시각을 담은 Claims Set의 예다.

#!syntax json
{
  "iss":"https://issuer.example",
  "sub":"user-123",
  "aud":"https://api.example",
  "iat":1788000000,
  "exp":1788003600,
  "scope":"profile:read order:write"
}

웹 서비스에서의 전형적인 흐름은 다음과 같다.

1. 사용자가 인증 서버에서 인증한다.
2. 인증 서버가 Access Token을 발급한다.
3. 클라이언트가 API 요청에 토큰을 함께 보낸다.
4. API 서버가 서명, 발급자, 수신자와 유효 시간을 검증한다.
5. 토큰의 Scope나 권할을 기준으로 요청을 허용하거나 거부한다.

일반적으로 많이 보는 서명 기반 JWT는 xxxxx.yyyyy.zzzzz처럼 마침표로 구분된 세 부분이다. 각각 보호된 헤더, 클레임을 담은 Payload, 서명(Signature) 또는 MAC을 뜻한다. 참고로 JWE 방식은 다섯 부분을 사용한다.

1.1. 처음 읽기 전에

용어 뜻
발급자(Issuer, iss) 토큰을 만들어 서명하는 서버
클라이언트(Client) 토큰을 받아 API 요청에 실어 보내는 앱, 브라우저 또는 다른 서버
리소스 서버(Resource Server) 토큰을 검증하고 실제 API를 제공하는 서버
클레임(Claim) 사용자 ID, 대상 API, 만료 시각처럼 토큰에 담긴 정보
수신자(Audience, aud) 이 토큰을 사용하도록 지정된 API 또는 서비스
Access Token 새 Access Token을 발급받기 위한 장기 자격 증명
JWT Set(JWKS) 여러 공개 키를 JSON으로 배포한 키 목록

1.2. 세션 방식과의 차이


전통적인 서버 세션에서는 클라이언트가 짧은 세션 ID를 보내고, 서버가 저장소에서 로그인 정보와 권한을 조회한다. JWT 방식은 필요한 정보를 토큰에 담아 API 서버가 서명을 직접 검증하도록 설계할 수 있다.
구분 서버 세션 JWT 로컬 검증
클라이언트가 보관하는 값 짧은 세션 ID 클레임과 서명이 포함된 토큰
요청마다 필요한 작업 세션 저장소 조회 서명과 클레임 검증
즉시 로그아웃 세션 삭제로 비교적 단순 별도 폐기 전략이 필요
여러 API에서 사용 공용 세션 저장소나 세션 복제가 필요할 수 있음 공개 키를 공유하면 각 API가 독립적으로 검증 가능
네트워크 크기 대체로 작음 클레임과 서명 때문에 더 큼

JWT가 항상 세션보다 빠르거나 가벼운 것은 아니다. 중앙 세션 저장소 조회를 줄이면 네트워크 왕복과 저장소 부하를 줄일 수 있지만, 서명 검증에는 CPU가 들고 토큰 크기도 커진다. 모든 요청에서 Redis 같은 인메모리DB에서 폐기 목록을 조회하면 서버 상태에 다시 의존적이게 된다.

1.3. 주로 쓰이는 경우

  • 여러 API나 마이크로서비스가 하나의 인증 서버에서 발급한 토큰을 검증해야 할 때
  • 서로 다른 언어로 만든 서비스 사이에서 표준화된 토큰을 교환할 때
  • 모바일 앱, SPA, 서버 간 호출처럼 세션 쿠키만으로 처리하기 불편한 클라이언트가 있을 대
  • 외부 파트너나 다른 조직에 제한된 권한을 담은 토큰을 전달해야 할 때
  • 공개 키를 이용해 발급 권한과 검증 권한을 분리해야 할 때

2. 구조


파일:JSON_vector_logo.svg


JWT의 Header와 Payload는 JSON 객체를 바탕으로 표현된다.

2.1. JWS 기반 JWT


서명 또는 MAC이 적용된 JWT는 보통 다음 세 부분으로 구성된다.

BASE64URL(Protected Header).BASE64URL(Payload).BASE64URL(Signature)

1. HEADER 2. PAYLOAD 3. SIGNATURE
알고리즘, 타입, 키 식별자 등 JWT Claims Set Header와 Payload를 대상으로 생성한 서명 또는 MAC

2.1.1. Protected Header


첫 번째 부분에는 서명 알고리즘, 토큰의 타입, 사용할 키를 찾기 위한 식별자 등이 들어간다.

#!syntax json
{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "key-2026-01"
}

alg는 서명 또는 MAC 알고리즘을, typ는 토큰의 타입을, kid는 여러 키 중 검증에 사용할 키를 찾는 식별자를 나타낼 수 있다.

2.1.2. Payload


두 번째 부분은 실제 클레임을 담은 JSON 객체이다.

#!syntax json
{
  "iss": "https://issuer.example",
  "sub": "user-123",
  "aud": "https://api.example",
  "exp": "1788003600"
}

Payload를 디코딩할 수 있다는 사실은 토큰이 유효하다는 뜻이 아니다. 서명과 필수 클레임을 모두 검증하기 전까지는 신뢰할 수 없는 입력값으로 취금해야 한다.

2.1.3. Signature


세 번째 부분은 Header와 Payload를 연결한 문자열을 대상으로 만든 서명 또는 MAC이다.

encodedHeader  = BASE64URL(UTF8(Header JSON))
encodedPayload = BASE64URL(Payload bytes)
signingInput   = encodedHeader + "." + encodedPayload
signature      = SIGN_OR_MAC(key, signingInput)
token          = encodedHeader + "." + encodedPayload + "." + BASE64URL(signature)

Header나 Payload가 바뀌면 서명 입력값도 달라지므로 정상적인 검증에 실패한다.

2.2. JWE 기반 JWT

내용 자체를 숨겨야 한다면 JWE를 사용할 수 있다. JWE는 클레임을 암호화해서 담는다. 서명만 하는 JWS와 달리 내용 자체를 감춘다. JWE Compact Serialization은 다음 다섯 부분으로 구성된다.
BASE64URL(Protected Header).BASE64URL(Encrypted Key).BASE64URL(Initalization Vector).BASE64URL(Ciphertext).BASE64URL(Authentication Tag)

부분 의미
Protected Header alg(키를 다루는 방식)와 enc(본문 암호화 알고리즘)
Encrypted Key 본문 암호화에 사용한 Content Encrypted Key(CEK)를 수신자 키로 감싼 값
Ciphertext 암호화된 JWT Claims Set
Authentication Tag 변조 여부를 확인하는 인증 태그

JWS의 alg는 서명 알고리즘이지만 JWE의 alg는 키 관리 알고리즘이다. 이름이 같아 혼동하기 쉽다.
구분 예 설명
alg(키 관리) RSA-OAEP-256, ECDH-ES+A256KW, A256KW, dir CEK를 수신자에게 전달하는 방식. dir은 미리 공유한 대칭 키를 CEK로 그대로 사용한다
enc(본문 암호화) A256GCM, A128CBC-HS256 Claims Set을 실제로 암호화하는 AEAD 알고리즘

2.3. 중첩 JWT

서명과 암호화를 함께 적용하려면 JWS를 만든 뒤 그것을 JWE로 감싼다. 이를 Nested JWT라고 하며, 바깥 JWE Header의 cty 값이 JWT로 표시된다.

순서를 뒤집어 암호화한 뒤 서명하면 서명자를 확인할 수는 있지만 서명자가 평문을 확인했다는 보장이 없어 부인방지 성질이 약해진다. RFC 7519는 서명 후 암호화를 권장한다.

2.4. JWE가 필요한 경우

  • 토큰 자체에 제3자에게 노출되면 안 되는 정보가 포함되어야 할 때
  • 토큰이 브라우저나 모바일처럼 사용자가 내용을 확인할 수 있는 경로를 지나고, 그 내용이 민감할 때
  • 외부 파트너에게 전달하는 토큰에 수신자 외에는 알 수 없어야 하는 값이 포함될 때

반대로 대부분의 API 인증에서는 JWS만으로 충분하다. JWE는 다음 비용을 함께 가져온다.
  • 다섯 부분과 암호문, 인증 태그 때문에 같은 클레임이라도 JWS보다 토큰이 커진다.
  • 서명 키와 별개로 암호화 키를 배포하고 교체해야 하며, 수신자마다 키가 다를 수 있다.
  • 복호화한 뒤에야 클레임을 확인할 수 있어 검증 비용과 디버깅 난이도가 올라간다.
  • 기밀성이 필요한 이유가 토큰 밖에 있는 경우가 많다. 전송 구간이 문제라면 HTTPS가, 저장 위치가 문제라면 쿠키 속성과 XXS 대책이 먼저다.

2.5. Base64url


JWT Compact 형식은 HTTP Header나 URL에서 다루기 쉬운 문자를 사용하기 위해 Base64url을 사용한다. 일반 Base64의 +, / 대신 -, _를 사용하고, JOSE Compact 표현에서는 끝의 = 패딩을 생략한다.

Base64url은 암호화가 아니다. JWS 기반 JWT의 Header와 Payload는 누구나 디코딩할 수 있으므로 비밀번호, 개인 키, API 비밀 키와 같은 민감 정보를 넣어서는 안 된다.

3. 주요 클레임

클레임 정식 명칭 의미
iss Issuer JWT를 발급한 주체
sub Subject JWT가 설명하는 사용자, 클라이언트 또는 대상
aud Audience JWT를 사용하도록 지정된 API 또는 서비스
exp Expiration Time JWT가 만료되는 시각
nbf Not Before JWT가 사용할 수 있게 되는 시각
iat Issued At JWT가 발급된 시각
jti JWT ID JWT를 구별하기 위한 식별자

RFC 7519만을 기준으로 하면 이 클레임들은 모두 선택 사항이다. 다만 OAuth 2.0, OpenID Connect 또는 개별 서비스의 규칙에서 일부를 필수로 정할 수 있다.

exp, nbf, iat에는 보통 1970년 1월 1일 00:00:00 UTC부터 경과한 초를 나타내는 NumbericDate가 사용된다. JavaScript의 Date.now()처럼 밀리초를 반환하는 API와 단위를 혼동하면 안 된다.

aud는 특히 중요하다. 다른 API를 위해 발급된 토큰을 현재 서비스가 받아들이면 안 되므로, 현재 서비스가 토큰의 수신자로 지정되어 있는지 확인해야 한다.

표준 클레임 외에도 roles, permissions, tenant_id처럼 서비스가 정한 사용자 정의 클레임을 넣을 수 있다. 다만 토큰에 너무 많은 정보를 넣으면 크기가 커지고, 발급 뒤 정보가 변경되어도 기존 토큰에는 과거 값이 남을 수 있다.

4. 발급과 검증

4.1. 발급

1. 전달할 사용자의 권한 정보를 클레임으로 정한다.
2. Header에 사용할 알고리즘과 키 식별자를 넣는다.
3. Header와 Payload를 Base64url로 인코딩한다.
4. 두 값을 마침표로 연결해 서명 입력값을 만든다.
5. 개인 키 또는 공유 비밀 키로 Signature나 MAC을 계산한다.
6. 결과를 세 번째 부분으로 붙여 JWT를 완성한다.

4.2. 검증

1. 토큰의 형식과 길이를 확인한다.
2. alg가 서버가 허용한 알고리즘인지 확인한다.
3. kid를 이용해 신뢰한 키 집합에서 검증 키를 선택한다.
4. Signature 또는 MAC을 검증한다.
5. iss가 신뢰한 발급자인지 확인한다.
6. aud에 현재 API가 포함되는지 확인한다.
7. exp와 nbf를 확인한다.
8. Scope, Role, permission 등 애플리케이션의 권한 규칙을 확인한다.
9. 하나라도 실패하면 전체 토큰을 거부한다.
형식 알고리즘 서명 클레임 권한
부분 수와 길이 허용 목록과 비교 키로 검증 iss, aud, exp, nbf Scope, Role, permission
한 단계라도 실패하면 토큰을 거부한다.

4.3. JWK Set과 키 교체


여러 공개 키를 JSON으로 배포한 목록을 JWK Set 또는 JWKS라고 한다. JWT Header의 kid와 비교해 검증에 사용할 키를 고른다.

공개 키 기반의 키 교체는 보통 다음 순서로 진행한다.

1. 기존 키 A로 토큰을 발급한다.
2. 새 키 B JWKS에 추가한다.
3. 새 토큰부터 키 B로 서명한다.
4. 기존 토큰이 유효한 동안 키 A도 JWKS에 유지한다.
5. 키 A로 서명된 토큰이 모두 만료된 뒤 키 A를 제거한다.

5. 알고리즘과 키

방식 예 특징
공유 비밀 키 기반 MAC HS256 발급자와 검증자가 같은 비밀 키를 공유한다. 키를 가진 쪽은 모두 토큰을 만들 수 있다.
공개 키 기반 전자서명 RS256, ES256, EdDSA 발급자는 개인 키로 서명하고 API 서버는 공개 키로 검증한다.

여러 API나 외부 파트너가 토큰을 검증해야 한다면 공개 키 기반 전자서명이 유리할 수 있다. 검증 서버에는 공개 키만 배포하므로 검증 권한과 발급 권한을 분리할 수 있기 때문이다.

토큰 Header의 alg 값만 보고 알고리즘을 선택해서는 안 된다. 서버가 미리 허용한 알고리즘을 정하고, 토큰의 값이 그 목록과 일치하는지 확인해야 한다.

파일:Digital signature.svg


개인 키로 서명하고 공개 키로 검증하는 전자서명의 기본 흐름.

6. OAuth 2.0·OpenID Connect와의 관계


OAuth 2.0은 보호된 자원에 접근할 권한을 위임하는 인가 프레임워크이고, JWT는 토큰 안의 정보를 표현하는 형식이다. OAuth 2.0의 Access Token은 JWT일 수도 있고, 서버가 별도로 조회하는 불투명한 문자열일 수도 있다.
토큰 주요 목적 주요 수신자
Access Token 보호된 API에 접근 리소스 서버(API)
Refresh Token 새 Access Token 발급 인증 서버
ID Token 로그인 결과와 사용자 인증 정보 전달 클라이언트 애플리케이션

OpenID Connect(OIDC)는 OAuth 2.0 위에 사용자 인증 기능을 추가한 프로토콜이다. OIDC의 ID Token은 JWT 형식이다. ID Token을 Access Token 대신 API 호출에 사용하면 안 된다.

Bearer Token은 토큰을 가진 사람이 별도의 키 소유 증명 없이 그 권한을 사용할 수 있는 방식이다. Bearer는 토큰의 데이터 형식이 아니므로, Bearer Token은 JWT일 수도 있고 불투명 토큰일 수도 있다.

Authorization: Bearer <Access Token>


파일:Web API.svg


클라이언트가 Web API에 요청하고 서버가 응답하는 기본 구조. JWT Access Token은 요청의 Authorization 헤더에 실어 보낼 수 있다.

7. 장점

7.1. 중앙 조회를 줄일 수 있음


API 서버가 JWT 서명과 클레임을 직접 검증하면 요청마다 인증 서버나 중앙 세션 저장소에 질의하지 않아도 된다. 따라서 시스템 구조에 따라 네트워크 왕복과 중앙 저장소 부하를 줄일 수 있다.

7.2. 마이크로서비스와 수평 확장에 유리할 수 있음


여러 서비스가 같은 공개 키나 JWKS를 사용하면 각 서비스가 독립적으로 토큰을 검증할 수 있다. 새 API 인스턴스를 추가할 때 세션 데이터를 복제하지 않아도 되는 구조를 만들 수 있어 마이크로서비스와 다중 리전 환경에 유리할 수 있다.

7.3. 언어와 플랫폼에 덜 종속됨


JWT와 JOSE 규격은 표준화되어 있으므로 JavaScript 서비스가 발급한 토큰을 Python, JVM, .NET, Go 등 다른 환경에 검증할 수 있다. 다만 알고리즘, 키 형식, 클레임 해석과 시간 단위가 일치해야 한다.

8. 단점과 운영 대책

8.1. 즉시 폐기가 어려움


서명과 만료 시각만으로 독립 검증하는 JWT는 이미 발급한 특정 토큰을 만료 전에 즉시 무효화하기 어렵다. 로그아웃이나 계정 정지, 비밀번호 변경을 즉시 반영해야 한다면 별도의 폐기 전략이 필요하다.
방법 설명 비용과 특징
짧은 Access Token + Refresh Token Access Token은 짧게 유지하고 Refresh Token으로 재발급 가장 흔한 기본 전략, Refresh Token 보호와 회전 정책 필요
Redis 폐기 목록(블랙리스트) 로그아웃 토큰의 iss와 jti를 만료 시각까지 저장 기기별 로그아웃과 동시 로그인 제어에 유리하지만 서버 상태가 필요
토큰 버전 사용자 계정에 토큰 버전을 저장하고 JWT의 버전과 비교 사용자 전체의 과거 토큰을 한 번에 무효화하기 쉬움
발급 기준 시각 비밀번호 변경 시각 이후에 발급된 토큰만 허용 계정 단위로 과거 토큰을 일괄 폐기할 때 유용
Introspection:불투명 토큰 인증 서버에 현재 활성 상태를 질의 중앙 통제가 쉬우나 네트워크 호출과 장애 의존성이 증가

Redis 폐기 목록의 단순한 예는 다음과 같다.

key = "jwt:deny:" + issuer + ":" + jti
TTL = exp - 현재 시각


토큰이 자연 만료되면 Redis 항목도 함께 사라지도록 TTL을 남은 유효 시간으로 설정할 수 있다. 원문 토큰 전체를 저장하기보다 발급자와 토큰 ID 조합을 사용하는 편이 관리하기 쉽다.

8.2. 권한 정보가 오래될 수 있음


JWT에 Role이나 Permissionㅇㄹ 넣으면 발급 뒤 사용자의 권한 변경되어도 기존 토큰에는 과거 값이 남는다. 짧은 만료 시간, 토큰 버전, 중요 요청에서의 서버 측 재확인 등을 조합할 수 있다.

8.3. 키 관리가 필요함


개인 키나 공유 비밀 키가 유출되면 공격자가 정상 토큰처럼 보이는 값을 만들 수 있다. 키를 안전하게 보관하고, kid를 사용해 교체하며, 오래된 키를 적절한 시점에 제거해야 한다.

8.4. 보안

  • 토큰의 alg를 그대로 믿지 말고 서버가 허용한 알고리즘 목록과 비교한다.
  • 서명을 먼저 검증한 뒤 Payload의 값을 신뢰한다.
  • iss, aud, exp, nbf를 서비스 규칙에 맞게 확인한다.
  • HMAC이나 Signature를 사람이 기억하기 쉬운 짧은 문자열을 사용하지 않는다.
  • 비밀번호, 개인 키, API Secret과 민감 개인정보를 JWS Payload에 넣지 않는다.
  • Bearer Token은 HTTPS로 전송한다.
  • JWT 전체를 애플리케이션 로그, 프록시 로그, 오류 추적 서비스에 남기지 않는다.
  • Access Token과 ID Token을 서로 같이 사용하지 않는다.
  • 브라우저 저장 위치는 XSS와 CSRF를 함께 고려한다. JavaScript 저장소는 XSS의 위험이 있고, HttpOnly Cookie는 CSRF 대책이 필요하다.
검증이 끝나기 전까지 Payload는 신뢰할 수 없는 외부 입력이다.

9. 구현체


JWT는 특정 언어나 프레임워크에 종속되지 않는다. JavaScrip·TypeScript, Python, JVM·Android, .net, Go, Rust, PHP, Ruby 등 대부분의 주요 환경에 구현체가 있다.

구현체를 선택할 때는 다음을 확인하는 것이 좋다.
  • 현재 유지보수되고 보안 공지가 제공되는가?
  • 필요한 JWS, JWE, JWK와 JWKS 기능을 지원하는가?
  • 허용 알고리즘을 애플리케이션 설정에서 고정할 수 있는가?
  • iss, aud, exp, nbf를 검증할 수 있는가?
  • 원격 JWKS 조회, 캐시와 키 교체를 안전하게 처리하는가?

더 많은 언어별 구현체는 JWT 라이브러리 목록에서 확인할 수 있다. 목록에 있다는 사실만으로 특정 라이브러리의 안정성과 유지보수 상태가 보증되는 것은 아니다.

10. JWT를 사용할지 결정할 때

요구사항 검토 방향
여러 API가 독립적으로 검증해야 함 공개 키 기반 JWT가 유용할 수 있음
특정 토큰을 즉시 폐기해야함 Redis 폐기 목록, 서버 세션 또는 불투명 토큰이 더 단순할 수 있음
권한이 자주 변경됨 짧은 만료 시간 또는 서버 측 권한 재확인이 필요
토큰에 큰 데이터가 필요함 JWT 크기와 HTTP Header 한계를 고려
민감한 정보를 전달해야함 JWS만으로는 부족하며 JWE 또는 별도 보안 채널을 검토
외부 시스템과 교환해야 함 알고리즘, 키 형식, 발급자와 수신자 규칙을 명확히 합의

JWT가 꼭 정답은 아니다, 세션방식이 꼭 나쁜것도 아니며 시스템의 규모, 즉시 폐기 요구, 장애 허용 범위와 운영 복잡도를 함께 보고 선택해야 한다.

11. 관련 문서

12. 외부 링크