본문 바로가기

스마트웹앱콘텐츠전문가/파이썬(플라스크, 데이터 처리)

Flask REST API에 Refresh Token 시스템 구현하기

728x90
반응형

Access Token 만료 걱정 끝! 실전 인증 설계 완성

 

JWT를 활용한 인증 시스템을 구축한 많은 개발자들이 처음 마주하는 고민이 있습니다.


바로 Access Token이 너무 빨리 만료된다면?
그때 필요한 것이 바로 Refresh Token 시스템입니다.


이번 글에서는 Flask 기반 REST API에 Access Token + Refresh Token을 도입하여 실전 보안 설계를 완성하는 방법을 소개합니다.

 

 

 

 


🧠 Refresh Token이란?

 

Access Token은 일반적으로 짧은 유효 기간을 가집니다 (예: 15분).


보안은 강화되지만, 클라이언트는 자주 로그인을 다시 해야 하는 불편함이 발생합니다.

그래서 사용하는 것이 Refresh Token입니다.


Refresh Token은 유효기간이 길고 서버에서 관리하며, Access Token이 만료되었을 때 새 토큰을 재발급하는 데 사용됩니다.

 

 

 

 

 

 

반응형

 

 

 

 

 


⚙️ 개발 환경 구성

 

📦 설치 라이브러리

pip install flask flask-jwt-extended

 

 

 

 

 


🧩 Flask 설정 + 기본 API 구성

 

from flask import Flask, jsonify, request
from flask_jwt_extended import (
    JWTManager, create_access_token, create_refresh_token,
    jwt_required, get_jwt_identity, jwt_refresh_token_required
)

app = Flask(__name__)
app.config['JWT_SECRET_KEY'] = 'super-secret-key'
app.config['JWT_ACCESS_TOKEN_EXPIRES'] = 900         # 15분
app.config['JWT_REFRESH_TOKEN_EXPIRES'] = 86400 * 7   # 7일

jwt = JWTManager(app)
users = {'user1': 'password123'}

 

 

 

 


🧾 1단계: 로그인 시 Access + Refresh Token 동시 발급

 

@app.route('/login', methods=['POST'])
def login():
    data = request.get_json()
    username = data.get('username')
    password = data.get('password')

    if users.get(username) != password:
        return jsonify({'msg': 'Invalid credentials'}), 401

    access_token = create_access_token(identity=username)
    refresh_token = create_refresh_token(identity=username)

    return jsonify(access_token=access_token, refresh_token=refresh_token), 200

 

클라이언트는 로그인 성공 시 두 개의 토큰을 받아 저장합니다.
Access Token은 Authorization 헤더로, Refresh Token은 별도 저장소(localStorage, Cookie 등)에 보관합니다.

 

 


🔄 2단계: Access Token 재발급 (Refresh Token 사용)

 

@app.route('/token/refresh', methods=['POST'])
@jwt_required(refresh=True)
def refresh():
    identity = get_jwt_identity()
    new_access_token = create_access_token(identity=identity)
    return jsonify(access_token=new_access_token), 200

 

✅ Access Token이 만료되면 클라이언트는 저장된 Refresh Token을 POST 요청에 담아 새 Access Token을 발급받습니다.

 

 

 

 


🔐 3단계: 보호된 API

 

@app.route('/mypage', methods=['GET'])
@jwt_required()
def mypage():
    user = get_jwt_identity()
    return jsonify({'msg': f'Hello, {user}'}), 200

 

 

 

 


🧪 테스트 흐름

 

1. 로그인 후 두 토큰 발급

curl -X POST http://localhost:5000/login \
-H "Content-Type: application/json" \
-d '{"username":"user1", "password":"password123"}'

 

2. 보호 API에 Access Token 사용

curl http://localhost:5000/mypage \
-H "Authorization: Bearer <access_token>"

 

3. Access Token 만료 후 Refresh Token으로 갱신

curl -X POST http://localhost:5000/token/refresh \
-H "Authorization: Bearer <refresh_token>"

 

 

 

 

 


🧠 보안 고려사항

 

항목 - 설명

Refresh Token 저장 방식 보안 강화를 위해 HttpOnly 쿠키 사용 권장
Refresh Token 탈취 방지 탈취 시 즉시 무효화해야 함 (서버 저장소 필요)
로그아웃 시 처리 서버 측에서 Refresh Token을 블랙리스트 처리 필요
자동 갱신 타이밍 Access Token 만료 직전 또는 401 응답 후 자동 재요청 처리

 

 

 

 


✅ 토큰 만료 시간 설정 예시

 

from datetime import timedelta

app.config['JWT_ACCESS_TOKEN_EXPIRES'] = timedelta(minutes=15)
app.config['JWT_REFRESH_TOKEN_EXPIRES'] = timedelta(days=7)

 

 

 

 


📌 요약

 

경로 - 메서드 - 설명

/login POST Access + Refresh Token 발급
/mypage GET Access Token 필요
/token/refresh POST Refresh Token으로 Access Token 갱신

 

 

 

 


 

Access Token + Refresh Token 시스템은
보안성과 사용자 편의성을 모두 잡을 수 있는 인증 구조입니다.
이제 더 이상 매번 로그인할 필요 없이,
만료된 토큰을 자동으로 갱신해 지속적이고 안전한 세션 유지가 가능합니다.

728x90
반응형