JWT(JSON Web Token) 은 사용자 인증 및 정보 교환을 위한 토큰 기반 인증 방식입니다.
JWT는 서버에서 인증 정보를 저장하지 않고 클라이언트에게 토큰을 발급하며, 이를 통해 무상태(Stateless) 인증을 구현할 수 있습니다.
📌 JWT의 주요 특징
✅ 무상태(State-less) → 서버가 세션을 저장하지 않음
✅ JSON 기반 → 데이터를 쉽게 인코딩하여 저장
✅ 보안 강화 → 서명(Signature)을 포함하여 변조 방지
✅ 다양한 환경에서 사용 가능 → REST API, GraphQL, OAuth, 모바일 앱 등

세션 기반 인증은 사용자의 로그인 정보를 서버의 메모리(RAM) 또는 데이터베이스(DB) 에 저장합니다. 따라서 사용자가 많아질수록 세션 저장 공간이 증가하여 서버 부하가 커짐.
무상태 인증은 서버가 인증 정보를 저장하지 않기 때문에, 부하 없이 인증 가능.
📌 예제: JWT 인증
GET /profile HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
✔️ 서버는 이 요청만으로 사용자를 인증할 수 있음 → DB 조회 불필요 → 성능 최적화
📌 JWT 인증 방식의 흐름
1. 사용자가 로그인 요청 (ID, PW)
2. 서버에서 사용자 정보 확인 후 JWT 토큰 발급
3. 클라이언트는 이후 모든 요청에 JWT를 포함하여 전송
4. 서버는 토큰을 검증하여 사용자 인증
ID와 비밀번호(PW)를 입력하여 서버에 로그인 요청을 보냄.POST /loginPOST /login HTTP/1.1
Content-Type: application/json
{
"username": "user1",
"password": "mypassword"
}
ID와 비밀번호를 확인.HTTP/1.1 200 OK
Content-Type: application/json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
✔️ JWT가 클라이언트에 반환됨.
Authorization 헤더에 Bearer Token 방식으로 전송.GET /user/profile HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 1,
"username": "user1",
"email": "user1@example.com"
}
JWT는 3개의 부분(헤더, 페이로드, 서명) 으로 구성됩니다.
📌 JWT 예제 (.으로 구분된 3개 섹션)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
📌 JWT 구조
| 파트 | 설명 | 예제 (Base64 인코딩) |
|------|------|-----------------|
| Header (헤더) | 토큰 타입(JWT)과 서명 알고리즘 지정 | { "alg": "HS256", "typ": "JWT" } |
| Payload (페이로드) | 사용자 정보 및 만료 시간 포함 | { "sub": "1234567890", "name": "John Doe", "exp": 1715610420 } |
| Signature (서명) | 토큰 변조 방지 | HMACSHA256(Base64(Header) + Base64(Payload) + Secret) |
📌 Flask를 이용한 JWT 인증 예제
from flask import Flask, request, jsonify
import jwt
import datetime
app = Flask(__name__)
SECRET_KEY = "mysecretkey"
# 사용자 로그인 엔드포인트 (JWT 발급)
@app.route("/login", methods=["POST"])
def login():
data = request.json
username = data.get("username")
password = data.get("password")
# 예제 사용자 검증 (실제 환경에서는 DB 조회 필요)
if username == "user1" and password == "mypassword":
token = jwt.encode(
{"username": username, "exp": datetime.datetime.utcnow() + datetime.timedelta(hours=1)},
SECRET_KEY,
algorithm="HS256"
)
return jsonify({"access_token": token})
return jsonify({"message": "Invalid credentials"}), 401
# JWT 검증 및 보호된 API 엔드포인트
@app.route("/protected", methods=["GET"])
def protected():
token = request.headers.get("Authorization")
if not token:
return jsonify({"message": "Token is missing!"}), 401
try:
decoded = jwt.decode(token.split(" ")[1], SECRET_KEY, algorithms=["HS256"])
return jsonify({"message": f"Hello, {decoded['username']}!"})
except jwt.ExpiredSignatureError:
return jsonify({"message": "Token expired!"}), 401
except jwt.InvalidTokenError:
return jsonify({"message": "Invalid token!"}), 401
if __name__ == "__main__":
app.run(debug=True)
📌 API 요청 예제
# 로그인 요청 (JWT 발급)
curl -X POST http://127.0.0.1:5000/login -H "Content-Type: application/json" -d '{"username": "user1", "password": "mypassword"}'
# 보호된 API 접근 (발급받은 JWT 사용)
curl -X GET http://127.0.0.1:5000/protected -H "Authorization: Bearer <JWT토큰>"
✅ HTTPS 사용 → JWT를 HTTP 대신 HTTPS에서 사용해야 함
✅ 토큰 만료 시간 설정 (exp) → 짧은 만료 시간을 설정하고 Refresh Token 사용
✅ Blacklist 시스템 적용 → 로그아웃 시 특정 JWT를 무효화
✅ 비밀키(Secret) 안전하게 관리 → .env 파일 사용, 환경 변수로 설정
✅ 토큰 저장 위치 보안 → localStorage보다 httpOnly 쿠키를 활용
무상태(Stateless) 인증은 서버가 사용자 인증 정보를 저장하지 않고, 클라이언트가 인증 정보를 직접 제공하는 방식입니다.
대표적인 예시가 JWT(JSON Web Token) 기반의 인증 방식입니다.
📌 예제: JWT 인증
GET /profile HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
✔️ 서버는 이 요청만으로 사용자를 인증할 수 있음 → DB 조회 불필요 → 성능 최적화
📌 예제: 로드 밸런싱 구조
클라이언트 → 서버 A (JWT 검증 후 응답)
클라이언트 → 서버 B (JWT 검증 후 응답)
✔️ 어떤 서버에 요청하든 동일한 JWT 검증이 가능 → 확장성 증가
📌 예제: JWT 인증 vs 세션 인증 비교
| 인증 방식 | 처리 과정 | 속도 |
|---------|---------|------|
| 세션 인증 | 1. 요청 → 2. DB에서 세션 조회 → 3. 응답 | 느림 (DB 조회 필요) |
| JWT 인증 | 1. 요청 → 2. 토큰 검증 (DB 조회 없음) → 3. 응답 | 빠름 (토큰만 검증) |
✔️ JWT는 DB 없이 토큰 검증만으로 인증이 가능 → 성능 향상
📌 예제: REST API에서 JWT 사용
GET /user/profile HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
✔️ API 서버는 클라이언트 상태를 저장하지 않고, 요청만 처리 → RESTful 원칙 준수
📌 JWT 서명 검증 예제
import jwt
SECRET_KEY = "mysecretkey"
def verify_token(token):
try:
decoded = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
return decoded # 인증 성공
except jwt.ExpiredSignatureError:
return "Token expired!" # 인증 실패
except jwt.InvalidTokenError:
return "Invalid token!" # 인증 실패
✔️ 서버가 토큰을 검증하면 변조 여부 확인 가능 → 보안성 향상
✅ 무상태 인증은 서버 부담을 줄이고, 확장성이 뛰어남
✅ JWT를 사용하면 DB 없이 빠르게 사용자 인증 가능
✅ RESTful API 및 마이크로서비스 아키텍처에 최적화됨
🚫 하지만, 로그아웃 처리와 보안 문제를 해결해야 함 (Blacklist, Refresh Token 사용)
궁금한 점
기존 웹 애플리케이션에서는 세션 기반 인증(Session-based Authentication)이 주로 사용되었어. 이 방식에서는 사용자가 로그인하면 서버가 세션을 생성하고, 세션 ID를 클라이언트에게 전달해서 이를 사용해 인증하는 방식이야. 하지만 이 방식에는 몇 가지 단점이 있었어.
JWT(JSON Web Token)의 기획 의도는 안전하고 확장성이 뛰어난 인증 방식을 제공하는 것이야. 이를 위해 자기 포함(Self-contained)된 인증 방식을 만들고, 서버의 부담을 줄이면서도 변조가 불가능한 인증 방식을 목표로 개발되었어.
기존의 세션 기반 인증 방식은 서버가 사용자 정보를 직접 관리해야 했지만, JWT는 클라이언트에게 필요한 정보를 포함한 토큰을 발급해주고, 이를 통해 인증을 수행할 수 있도록 설계되었어.
✅ 목표: 사용자가 로그인할 때 서버가 토큰을 발급하고, 이후에는 서버가 별도로 사용자 상태를 저장하지 않더라도 인증할 수 있도록 함.
JWT는 OAuth 2.0 등의 인증 방식과 잘 어울리도록 설계되었어. 특히 OAuth 2.0에서 Access Token으로 많이 사용되고 있어.
✅ 목표: 다양한 웹/모바일/서드파티 애플리케이션과 쉽게 연동될 수 있도록 설계.
JWT의 기획 의도는 보안성, 확장성, 효율성을 모두 고려하여 분산 환경에서도 안정적으로 인증을 수행할 수 있도록 하는 것이야. 즉, 세션 기반 인증의 한계를 극복하고, 현대적인 웹 및 모바일 애플리케이션에서 쉽게 사용할 수 있는 인증 방식을 제공하는 것이 핵심 목적이야.