JWT인증 방식 써봤니?

낚시하는 곰·2025년 3월 12일

krafton jungle

목록 보기
4/52

1. JWT란?

JWT(JSON Web Token)사용자 인증 및 정보 교환을 위한 토큰 기반 인증 방식입니다.
JWT는 서버에서 인증 정보를 저장하지 않고 클라이언트에게 토큰을 발급하며, 이를 통해 무상태(Stateless) 인증을 구현할 수 있습니다.

📌 JWT의 주요 특징
무상태(State-less) → 서버가 세션을 저장하지 않음
JSON 기반 → 데이터를 쉽게 인코딩하여 저장
보안 강화 → 서명(Signature)을 포함하여 변조 방지
다양한 환경에서 사용 가능 → REST API, GraphQL, OAuth, 모바일 앱 등

무상태 인증이 왜 좋은걸까?

서버 부하 감소 (Scale-out 구조에 유리)

세션 기반 인증은 사용자의 로그인 정보를 서버의 메모리(RAM) 또는 데이터베이스(DB) 에 저장합니다. 따라서 사용자가 많아질수록 세션 저장 공간이 증가하여 서버 부하가 커짐.

무상태 인증은 서버가 인증 정보를 저장하지 않기 때문에, 부하 없이 인증 가능.

📌 예제: JWT 인증

GET /profile HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

✔️ 서버는 이 요청만으로 사용자를 인증할 수 있음 → DB 조회 불필요 → 성능 최적화


2. JWT 인증 과정 개요

📌 JWT 인증 방식의 흐름

1. 사용자가 로그인 요청 (ID, PW)
2. 서버에서 사용자 정보 확인 후 JWT 토큰 발급
3. 클라이언트는 이후 모든 요청에 JWT를 포함하여 전송
4. 서버는 토큰을 검증하여 사용자 인증

3. JWT 인증 과정 단계별 설명

🔹 1️⃣ 사용자 로그인 요청

  • 사용자가 ID비밀번호(PW)를 입력하여 서버에 로그인 요청을 보냄.
  • 요청 방식: POST /login
  • 요청 예제:
POST /login HTTP/1.1
Content-Type: application/json

{
  "username": "user1",
  "password": "mypassword"
}

🔹 2️⃣ 서버에서 사용자 인증 & JWT 발급

  • 서버는 데이터베이스(DB) 에서 사용자의 ID비밀번호를 확인.
  • 인증이 성공하면 JWT를 생성하여 클라이언트에 반환.
  • 응답 예제:
HTTP/1.1 200 OK
Content-Type: application/json

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

✔️ JWT가 클라이언트에 반환됨.


🔹 3️⃣ 클라이언트는 요청 시 JWT를 포함하여 전송

  • 이후 사용자는 모든 요청에 JWT를 포함하여 서버에 인증.
  • JWT는 Authorization 헤더에 Bearer Token 방식으로 전송.
GET /user/profile HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

🔹 4️⃣ 서버는 JWT 검증 후 요청 처리

  • 서버는 받은 JWT가 변조되지 않았는지 검증.
  • 검증이 성공하면 요청을 정상 처리하고 데이터를 반환.
  • 응답 예제:
HTTP/1.1 200 OK
Content-Type: application/json

{
  "id": 1,
  "username": "user1",
  "email": "user1@example.com"
}

5. JWT의 구조

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) |


7. JWT 구현 예제 (Flask)

📌 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토큰>"

8. JWT Best Practices (보안 강화)

HTTPS 사용 → JWT를 HTTP 대신 HTTPS에서 사용해야 함
토큰 만료 시간 설정 (exp) → 짧은 만료 시간을 설정하고 Refresh Token 사용
Blacklist 시스템 적용 → 로그아웃 시 특정 JWT를 무효화
비밀키(Secret) 안전하게 관리.env 파일 사용, 환경 변수로 설정
토큰 저장 위치 보안localStorage보다 httpOnly 쿠키를 활용


9. 결론: JWT 인증이 적합한 경우

  • RESTful API, 마이크로서비스 환경에서 무상태 인증이 필요한 경우
  • API 인증 시스템 (모바일, 웹 앱)
  • OAuth 2.0 및 SSO (Single Sign-On) 시스템

1. 무상태 인증(Stateless Authentication)이란?

무상태(Stateless) 인증서버가 사용자 인증 정보를 저장하지 않고, 클라이언트가 인증 정보를 직접 제공하는 방식입니다.
대표적인 예시가 JWT(JSON Web Token) 기반의 인증 방식입니다.


2. 무상태 인증의 장점

✅ 1️⃣ 서버 부하 감소 (Scale-out 구조에 유리)

  • 세션 기반 인증은 사용자의 로그인 정보를 서버의 메모리(RAM) 또는 데이터베이스(DB) 에 저장합니다.
  • 사용자가 많아질수록 세션 저장 공간이 증가하여 서버 부하가 커짐.
  • 무상태 인증서버가 인증 정보를 저장하지 않기 때문에, 부하 없이 인증 가능.

📌 예제: JWT 인증

GET /profile HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

✔️ 서버는 이 요청만으로 사용자를 인증할 수 있음 → DB 조회 불필요 → 성능 최적화


✅ 2️⃣ 확장성(Scalability) 뛰어남 (마이크로서비스 & 로드 밸런싱 최적화)

  • 세션 기반 인증은 서버가 인증 정보를 저장하므로 로드 밸런싱이 어렵다.
    • ex) 사용자가 서버 A에서 로그인했는데, 다음 요청이 서버 B로 가면 세션 정보가 없음.
    • 해결하려면 세션을 공유(Sticky Session) 해야 하지만, 성능과 유지보수에 부담.
  • 무상태 인증은 어떤 서버에서든 JWT를 검증할 수 있어 로드 밸런싱에 유리.

📌 예제: 로드 밸런싱 구조

클라이언트 → 서버 A (JWT 검증 후 응답)  
클라이언트 → 서버 B (JWT 검증 후 응답)  

✔️ 어떤 서버에 요청하든 동일한 JWT 검증이 가능 → 확장성 증가


✅ 3️⃣ 빠른 인증 처리 (DB 조회 불필요)

  • 세션 기반 인증은 매 요청마다 DB에서 세션 정보 조회가 필요.
  • 무상태 인증JWT 토큰만 검증하면 되므로, 훨씬 빠르게 인증할 수 있음.

📌 예제: JWT 인증 vs 세션 인증 비교
| 인증 방식 | 처리 과정 | 속도 |
|---------|---------|------|
| 세션 인증 | 1. 요청 → 2. DB에서 세션 조회 → 3. 응답 | 느림 (DB 조회 필요) |
| JWT 인증 | 1. 요청 → 2. 토큰 검증 (DB 조회 없음) → 3. 응답 | 빠름 (토큰만 검증) |

✔️ JWT는 DB 없이 토큰 검증만으로 인증이 가능 → 성능 향상


✅ 4️⃣ API 기반 시스템에 최적화 (RESTful API, GraphQL)

  • REST API는 무상태(Stateless) 원칙을 따름.
  • 따라서, API 서버가 클라이언트의 상태를 저장하지 않는 무상태 인증이 적합.

📌 예제: REST API에서 JWT 사용

GET /user/profile HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

✔️ API 서버는 클라이언트 상태를 저장하지 않고, 요청만 처리 → RESTful 원칙 준수


✅ 5️⃣ 보안 강화 (토큰 서명으로 변조 방지)

  • JWT는 서명(Signature)을 포함하여 변조를 방지할 수 있음.
  • 세션 기반 인증보다 토큰이 변조되지 않았는지 쉽게 검증 가능.

📌 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!"  # 인증 실패

✔️ 서버가 토큰을 검증하면 변조 여부 확인 가능 → 보안성 향상


5. 정리

무상태 인증은 서버 부담을 줄이고, 확장성이 뛰어남
JWT를 사용하면 DB 없이 빠르게 사용자 인증 가능
RESTful API 및 마이크로서비스 아키텍처에 최적화됨
🚫 하지만, 로그아웃 처리와 보안 문제를 해결해야 함 (Blacklist, Refresh Token 사용)


궁금한 점

  • 장점이 많은 건 알겠는데 무슨 의도로 만든걸까?

1. 세션 기반 인증의 문제점

기존 웹 애플리케이션에서는 세션 기반 인증(Session-based Authentication)이 주로 사용되었어. 이 방식에서는 사용자가 로그인하면 서버가 세션을 생성하고, 세션 ID를 클라이언트에게 전달해서 이를 사용해 인증하는 방식이야. 하지만 이 방식에는 몇 가지 단점이 있었어.

서버 부하 증가:

  • 각 사용자의 세션을 서버가 저장해야 하기 때문에 사용자가 많아질수록 서버의 메모리와 성능이 부담됨.
  • 분산 환경에서의 어려움: 서버가 여러 개일 경우(로드 밸런싱 환경), 세션을 공유해야 해서 Redis 같은 별도 세션 저장소가 필요함.
  • 확장성이 부족함: 세션 정보를 중앙에서 관리해야 하므로 확장성이 떨어짐.

JWT의 기획 의도

JWT(JSON Web Token)의 기획 의도는 안전하고 확장성이 뛰어난 인증 방식을 제공하는 것이야. 이를 위해 자기 포함(Self-contained)된 인증 방식을 만들고, 서버의 부담을 줄이면서도 변조가 불가능한 인증 방식을 목표로 개발되었어.

1. 인증(Authentication)과 권한 부여(Authorization) 간소화

기존의 세션 기반 인증 방식은 서버가 사용자 정보를 직접 관리해야 했지만, JWT는 클라이언트에게 필요한 정보를 포함한 토큰을 발급해주고, 이를 통해 인증을 수행할 수 있도록 설계되었어.

✅ 목표: 사용자가 로그인할 때 서버가 토큰을 발급하고, 이후에는 서버가 별도로 사용자 상태를 저장하지 않더라도 인증할 수 있도록 함.

2. OAuth와 같은 표준 인증 방식과의 호환성

JWT는 OAuth 2.0 등의 인증 방식과 잘 어울리도록 설계되었어. 특히 OAuth 2.0에서 Access Token으로 많이 사용되고 있어.

✅ 목표: 다양한 웹/모바일/서드파티 애플리케이션과 쉽게 연동될 수 있도록 설계.

결론

JWT의 기획 의도는 보안성, 확장성, 효율성을 모두 고려하여 분산 환경에서도 안정적으로 인증을 수행할 수 있도록 하는 것이야. 즉, 세션 기반 인증의 한계를 극복하고, 현대적인 웹 및 모바일 애플리케이션에서 쉽게 사용할 수 있는 인증 방식을 제공하는 것이 핵심 목적이야.

profile
취업 준비생 낚곰입니다!! 반갑습니다!!

0개의 댓글