본문 바로가기

JWT(Json Web Token)

by Tech.Knockknows 2025. 9. 6.

JWT(Json Web Token)는 웹에서 사용자 인증과 정보 교환에 널리 쓰이는 토큰 기반 인증 방식이에요. 세 부분(Header, Payload, Signature)으로 구성되어 있고, Base64URL로 인코딩되어 문자열 한 줄로 표현됩니다. 서버는 사용자가 로그인하면 JWT를 발급하고, 클라이언트는 이후 요청마다 이 토큰을 전송해 인증을 대신할 수 있습니다. JWT는 세션 저장소가 필요 없어 확장성이 높고, API 서버나 마이크로서비스 간의 인증에도 자주 활용됩니다. 다만 토큰이 탈취되면 위험하므로 HTTPS 사용과 만료 시간(exp) 설정, 재발급 전략이 반드시 필요합니다.

이번 글에서는 JWT(JSON Web Token)에 대해 알아볼게요. JWT(JSON Web Token)는 로그인 후에 사용자가 자신이 누구인지 증명하는 “디지털 출입증”이에요. 길게 생긴 문자열 하나로 되어 있고, 서버는 이 출입증이 위조되지 않았는지를 확인해서 요청을 허용하거나 막아요.

 

쉽게 이해하기(비유)

회사 출입 시스템을 떠올려봐요. 사원증(= JWT)에는 전자서명이 들어 있고, 출입 게이트(= 서버)는 사원증의 서명이 유효한지와 유효기간이 지나지 않았는지를 확인한 뒤 통과시켜요. 사원증 표면의 정보(페이로드)는 누구나 읽을 수 있지만, 전자서명 덕분에 내용을 바꾸면 바로 위조로 판별돼요.

 

JWT 비유 이미지

한 줄 요약

  • JWT = 위조 방지 서명이 붙은 정보 조각(문자열)
  • 누구나 내용을 읽을 수는 있지만 서명 때문에 마음대로 바꿀 수는 없어요
  • 로그인 후 발급 → 요청 때마다 함께 보내서 인증

 

JWT 사용하는 이유

핵심은 확장성단순함이에요. 서버가 로그인 상태를 일일이 기억하지 않아도, 사용자가 들고 온 토큰만 확인하면 돼요.

 

세션 방식과 차이

  • 세션: 서버가 “로그인표”를 기억해요 → 서버가 많아지면 공유/동기화가 번거로워요.
  • JWT: 서버가 로그인표를 기억하지 않아요 → 사용자가 토큰을 들고 다니고, 서버는 서명 검증만 해요.

 

장점/주의점

  • 장점: 확장성 좋음, 마이크로서비스/모바일/서버리스 환경에 잘 맞아요.
  • 주의: 민감정보는 넣지 않기(누구나 디코딩 가능), 만료시간(exp) 설정 필수, HTTPS 필수.

 

JWT 구조

JWT는 헤더 · 페이로드 · 서명 세 부분을 점(.)으로 연결한 문자열이에요. 각 부분은 Base64URL로 인코딩돼요.

여기서 페이로드는 토큰 안에 들어가는 클레임(Claims) 집합으로, 사용자 정보와 토큰의 속성들을 담고 있어요.

이 부분은 Base64Url로 인코딩만 되어 누구나 읽을 수 있으므로, 민감한 데이터는 넣지 않는 게 원칙이에요.

 

헤더/페이로드/서명

JWT를 만들고 나면 아래와 같은 형식으로 생성돼요.

DOT(.)을 기준으로 총 3개의 데이터로 나뉘어지죠.

Tokenheader.payload.signature
JWT
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ik5vY2siLCJleHAiOjE3MDAwMDAwMDB9.
TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

데이터 구조를 앞에서 부터 순차적으로 보면 다음과 같아요.

  • 헤더: 사용한 알고리즘(예: HS256), 토큰 타입(JWT)
  • 페이로드: 사용자 ID, 권한, 만료시간 등 (민감정보는 금지)
  • 서명: 헤더+페이로드에 비밀키로 도장 찍은 값 → 위조 방지

대표 클레임과 예시

JWT 클레임(Claim)은 토큰의 페이로드(Payload) 안에 담기는

정보 조각으로 누가(Token 주체) 어떤 권한을 가지고 있는지 등을 나타내요.


대표적으로 등록 클레임(iss, sub, exp 등 표준화된 키),

공개 클레임(공유 가능한 커스텀 정보), 비공개 클레임(서버 간 협의로 정의된 정보)이 있어요.


서버는 이 클레임을 확인해 사용자 인증 상태와 권한을 판단해요.
즉, JWT의 본질은 클레임 집합을 안전하게 전달하는 구조라고 볼 수 있어요.

 

클레임 종류

 

일반적으로 클레임 종류는 다음과 같아요.

구분 설명 주요 예시 키 특징
등록 클레임
(Registered Claims)
JWT 표준에서 정의한 필수/권장 클레임.
토큰의 발급·만료·대상 등을 명확히 함.
iss(발급자), sub(주체), aud(대상자), exp(만료), nbf(사용가능시작), iat(발급시각), jti(토큰 ID) 사용 권장. 다른 시스템/라이브러리와 호환성 ↑
공개 클레임
(Public Claims)
사용자 정의 가능하지만, 이름 충돌 방지를 위해 IANA 레지스트리나 URI 네임스페이스 권장. role: "admin", permissions: ["read","write"] 확장성 있음. 표준과 혼용 가능
비공개 클레임
(Private Claims)
발급자와 수신자 간 협의된 클레임.
내부 전용 데이터 교환에 사용.
company_id: "eicn123", department: "sales" 자유롭게 정의 가능. 외부 호환성은 낮음

 

그래서 페이로드 안에 담긴 클레임의 예시 샘플을 만들어보면 아래와 같이 볼 수 있어요.

JWTClaims
Example
{
  "sub": "user_123",        // 사용자 식별자
  "name": "Knock",
  "role": "editor",
  "iat": 1700000000,        // 발급 시간
  "exp": 1700003600,        // 만료 시간
  "aud": "api.example.com"  // 대상(토큰 수신자)
}

 

이러한 클레임은 강제적으로 지킬 필요는 없어요. 하지만 등록 클레임(Registered Claims)의 경우

표준으로 정해진거라 사용할 경우 다른 서비스나 라이브러리와의 호환성이 좋아져요.

 

공개 클레임은 IANA나 URI 네임 스페이스를 통해 필요할때 등록해서 사용하면돼요. 이름 충돌만 피하면 되는거죠.

비공개 클레임은 외부 인터넷으로 나가지않고 내부에서만 사용하는 용도로 자유럽게 정의할 수 있어요.

 

보통 일반적으로 식별자, 사용자 이름, 토큰의 발급 및 만료시간 정도는 등록 클레임에 맞춰서 포함시켜요.

 

JWT 생성 방법(시크릿 기반: HS256)

가장 많이 쓰는 방법 중 하나가 HS256(HMAC-SHA256) 알고리즘이에요. 하나의 시크릿 키로 서명과 검증을 모두 해요.

 

Shell 스크립트로 만들기 (Linux/macOS, HS256)

Linux/macOS 환경에서는 별도의 외부 라이브러리 없이 openssl과 기본 유틸로 HS256 JWT를 직접 만들 수 있어요. Base64URL 인코딩과 HMAC-SHA256 서명이 핵심이에요.

아래 스크립트를 통해 JWT를 만들 수 있어요.

 

HEADER = '{"alg":"HS256","typ":"JWT"}'
PAYLOAD = '{"sub":"user_123","name":"Knock","aud":"api.example.com","exp":'$(($(date +%s)+3600))'}'

ScriptLinux/macOS
HS256
#!/usr/bin/env bash
set -euo pipefail

SECRET=${JWT_SECRET:-"dev-secret-change-me"}

b64url() {
  # stdin -> base64url (no padding, +/ replaced)
  openssl base64 -A | tr '+/' '-_' | tr -d '='
}

HEADER='{"alg":"HS256","typ":"JWT"}'
PAYLOAD='{"sub":"user_123","name":"Knock","aud":"api.example.com","exp":'$(($(date +%s)+3600))'}'

HEADER_B64=$(printf '%s' "$HEADER" | b64url)
PAYLOAD_B64=$(printf '%s' "$PAYLOAD" | b64url)

MSG="${HEADER_B64}.${PAYLOAD_B64}"

SIG=$(printf '%s' "$MSG" | openssl dgst -sha256 -hmac "$SECRET" -binary | b64url)

TOKEN="${MSG}.${SIG}"
echo "$TOKEN"

실행:

RunLinux/macOS
HS256
chmod +x make-jwt.sh
export JWT_SECRET="$(openssl rand -base64 32)"
./make-jwt.sh

JWT Token Generate

PowerShell로 만들기 (Windows, HS256)

Windows 환경에서는 기본 내장된 PowerShell만으로도 HS256 JWT를 만들 수 있어요.

Base64URL 인코딩과 HMACSHA256 서명을 직접 구현해요.

ScriptWindows PowerShell
HS256
Param(
  [string]$Secret = $env:JWT_SECRET
)

if (-not $Secret) { Write-Error "JWT_SECRET 환경변수가 필요해요."; exit 1 }

function To-Base64Url([byte[]]$bytes) {
  $s = [Convert]::ToBase64String($bytes)
  $s = $s.TrimEnd('=') -replace '\+','-' -replace '/','_'
  return $s
}

function B64Url-From-String([string]$text) {
  return To-Base64Url([Text.Encoding]::UTF8.GetBytes($text))
}

$header = '{"alg":"HS256","typ":"JWT"}'
$exp = [int][double]::Parse((Get-Date -UFormat %s)) + 3600
$payload = '{"sub":"user_123","name":"Knock","aud":"api.example.com","exp":' + $exp + '}'

$h = B64Url-From-String $header
$p = B64Url-From-String $payload
$msg = "$h.$p"

$hmac = New-Object System.Security.Cryptography.HMACSHA256
$hmac.Key = [Text.Encoding]::UTF8.GetBytes($Secret)
$signatureBytes = $hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($msg))
$sig = To-Base64Url $signatureBytes

$token = "$msg.$sig"
Write-Output $token

실행:

RunWindows PowerShell
HS256
$env:JWT_SECRET = [Convert]::ToBase64String((1..32 | ForEach-Object {Get-Random -Minimum 0 -Maximum 256}))
.\Make-Jwt.ps1

 

사전 준비 

사전에 준비할건 하나예요. '시크릿 키'를 준비해야해요. 이 '시크릿 키'가 전자서명을 검증하는데 사용하는 핵심이에요.

  • 시크릿 키는 길고 예측 불가능하게(예: 32바이트 이상 랜덤).
  • Git에 올리지 말고 환경변수시크릿 매니저에 보관.
  • 테스트용은 간단히, 운영용은 꼭 회전(로테이션) 전략 고려.

 

Python으로 만들기 (Linux/macOS & Windows)

Python에서는 PyJWT를 사용해요. OS에 상관없이 동일하게 동작해요.

먼저 안전한 사용을 위해 환경변수에 등록해요.

Linux/macOS 환경변수 등

 
EnvLinux/macOS
Secret
export JWT_SECRET="$(openssl rand -base64 32)"
echo $JWT_SECRET

 

Windows 환경 변수 등록

 
EnvWindows PowerShell
Secret
$env:JWT_SECRET = [Convert]::ToBase64String((New-Object byte[] 32 | ForEach-Object{$_=Get-Random -Minimum 0 -Maximum 256;$_}))
$env:JWT_SECRET

 

JWT 생성

 

환경변수에 등록했다면, 아래 파이썬 스크립트를 생성하고 실행해주세요.

실행하면 JWT 토큰이 생성돼요.
*(PyJWT 패키지는 설치되어 있어야해요.)

Codesign.py
HS256
import os, time, jwt

secret = os.getenv("JWT_SECRET")
if not secret:
    raise SystemExit("JWT_SECRET 환경변수가 필요해요.")

payload = {
    "sub": "user_123",
    "name": "Knock",
    "role": "editor",
    "aud": "api.example.com",
    "iat": int(time.time()),
    "exp": int(time.time()) + 3600  # 1시간 뒤 만료
}

token = jwt.encode(payload, secret, algorithm="HS256")
print("JWT:", token)
RunLinux/macOS & Windows
Python
python sign.py

JWT 발급 스크립트 실행

 

JWT 활용 & 실제 예시

JWT는 주로 웹·모바일 애플리케이션의 인증/인가에 활용되어 로그인 세션을 대체해요.

또한 API 서버 간 통신에서 신뢰할 수 있는 인증 수단으로 사용돼요.
더 나아가 마이크로서비스 아키텍처에서 서비스 간 권한 검증을 간단히 처리할 때도 많이 쓰여요.

HTTP 요청에서 사용(Authorization: Bearer)

HTTPAuthorization 헤더
Request
GET https://api.example.com/v1/profile
Authorization: Bearer <JWT>

그래서 대표적인 HTTP 요청으로 살펴보면 클라이언트(사용자)가 서버에 JWT 토큰을 포함한 요청을 보내면,

서버는 JWT를 꺼내 서명, 만료(exp), 대상(aud) 등을 확인하고 정상일 때만 응답해요.

 

N8N에서 JWT 인증 적용

또는 자동화로 많이 사용하는  N8N에서도 JWT 토큰으로 인증을 넣을 수 있어요.
HTTP Request Node
또는 Webhook Node에서 인증으로 사용할 수 있어요.

 

아래는 HTTP Request Node에 적용하는 화면이에요.

  1. CredentialsNewHTTP Header Auth
  2. Header Name: Authorization, Value: Bearer <JWT>
  3. HTTP Request 노드 → Authentication - Generic Credential Type - Bearer Auth 선택

HTTP Request JWT Authentication 설정

자주 발생하는 문제들

아래는 JWT를 활용할 때 자주 발생하는 문제들이에요.

특히 시스템 시간이 다르면 토큰 내 발급 / 만료 시간이 달라져서 유효하지 않은 토큰으로 인식될 경우가 종종 발생해요.

그래서 같은 NTP 서버로 맞춰서 시간대를 동기화 시켜줘야해요.

  • 시계 오차: 서버/클라이언트 시간이 크게 다르면 exp/iat 검증 실패 → NTP 동기화 권장.
  • 토큰 크기: 너무 크면 쿠키/URL 제한에 걸릴 수 있어요 → 보통 Authorization 헤더로 전송.
  • 알고리즘 강제: 검증 시 alg를 고정(예: alg=HS256)해 주세요.
  • 비밀키 유출: 유출 시 즉시 키 교체/토큰 폐기, 로그 점검 필요.

 

 


JWT 공식 사이트 : https://www.jwt.io/introduction#what-is-json-web-token

 

JSON Web Token Introduction - jwt.io

Learn about JSON Web Tokens, what are they, how they work, when and why you should use them.

www.jwt.io

 

JWT 디버거 : https://www.jwt.io/

 

JSON Web Tokens - jwt.io

JSON Web Token (JWT) is a compact URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is digitally signed using JSON Web Signature (JWS).

www.jwt.io

 

'기타' 카테고리의 다른 글

파일질라(Filezila) 기본 사용법  (2) 2025.09.02