Ответ
Refresh Token — это специальный, долгоживущий токен, который используется для безопасного получения нового, короткоживущего Access Token без необходимости повторного ввода логина и пароля пользователем.
Зачем это нужно?
Основная цель — повысить безопасность. Access Token, который предоставляет доступ к ресурсам, имеет очень короткий срок жизни (например, 15 минут). Если его перехватят, злоумышленник сможет использовать его лишь в течение этого короткого времени. Refresh Token живёт дольше (дни или недели), но может быть использован только для одной цели — запроса нового Access Token.
Типичный сценарий работы:
- Пользователь входит в систему, сервер выдает пару токенов:
access_token
иrefresh_token
. - Клиент использует
access_token
для всех запросов к защищенным ресурсам. - Когда
access_token
истекает, клиент получает ошибку401 Unauthorized
. - Клиент отправляет
refresh_token
на специальный эндпоинт (например,/api/token/refresh
). - Сервер проверяет
refresh_token
и, если он валиден, выпускает новую пару токенов.
Пример реализации на Python с PyJWT:
import jwt
import datetime
from flask import Flask, jsonify, request
app = Flask(__name__)
SECRET_KEY = "your-super-secret-key"
# Примерная база данных валидных refresh токенов
VALID_REFRESH_TOKENS = set()
@app.route('/login', methods=['POST'])
def login():
# ... (проверка логина и пароля) ...
user_id = 123
# Создаем Access Token на 15 минут
access_token = jwt.encode(
{"user_id": user_id, "exp": datetime.datetime.utcnow() + datetime.timedelta(minutes=15)},
SECRET_KEY, algorithm="HS256"
)
# Создаем Refresh Token на 7 дней
refresh_token = jwt.encode(
{"user_id": user_id, "exp": datetime.datetime.utcnow() + datetime.timedelta(days=7)},
SECRET_KEY, algorithm="HS256"
)
VALID_REFRESH_TOKENS.add(refresh_token) # Сохраняем токен как валидный
return jsonify({"access_token": access_token, "refresh_token": refresh_token})
@app.route('/refresh', methods=['POST'])
def refresh():
token = request.json.get('refresh_token')
if not token or token not in VALID_REFRESH_TOKENS:
return jsonify({"error": "Invalid or expired refresh token"}), 401
try:
# Декодируем, чтобы получить user_id для нового токена
data = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
user_id = data['user_id']
# Выдаем новый Access Token
new_access_token = jwt.encode(
{"user_id": user_id, "exp": datetime.datetime.utcnow() + datetime.timedelta(minutes=15)},
SECRET_KEY, algorithm="HS256"
)
return jsonify({"access_token": new_access_token})
except jwt.ExpiredSignatureError:
return jsonify({"error": "Refresh token expired"}), 401
Ключевые аспекты безопасности:
- Хранение: Refresh Token должен храниться в безопасном месте на клиенте (например, в
HttpOnly
cookie). - Отзыв: При выходе пользователя из системы (logout) или при подозрении на компрометацию Refresh Token должен быть немедленно отозван на сервере.