Ответ
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 должен храниться в безопасном месте на клиенте (например, в
HttpOnlycookie). - Отзыв: При выходе пользователя из системы (logout) или при подозрении на компрометацию Refresh Token должен быть немедленно отозван на сервере.
Ответ 18+ 🔞
Слушай, а вот эта вся хуйня с Refresh Token — это ж просто гениальная идея, если вдуматься! Ну представь: ты заходишь в приложение, вводишь логин-пароль, а потом тебя на неделю, блядь, не выкидывает, хотя сам ключ доступа живёт 15 минут. Магия, сука!
А нахуя это вообще нужно?
Да чтобы не подставляться, как последний лох! Access Token — это как пропуск в закрытый клуб. Дали тебе его на 15 минут, и если какой-то пидарас его украдёт, то он только на эти 15 минут станет тобой, а потом — пиздец, фантик. А Refresh Token — это типа доверенная бумажка, по которой тебе в гардеробе выдают новый пропуск. Да, она живёт долго (неделю, например), но её нихуя нельзя использовать, чтобы сразу в бар пройти — только для одного дела: обменять на новый короткий пропуск.
Как это выглядит в жизни, ёпта:
- Залогинился — получил два ключа:
access_token(быстрый) иrefresh_token(долгий). - Ходишь по защищённым страницам с быстрым ключом.
- Внезапно получаешь в ебало ошибку
401— ключ-то сдох, блядь. - Не паникуешь! Суёшь свой долгий
refresh_tokenв специальную дырочку на сервере (/api/token/refresh). - Сервер смотрит: "А, ну этот чувак свой, валидный ещё". И выдаёт тебе НОВУЮ парочку токенов. И пошло-поехало опять.
Вот, смотри, как это в коде может выглядеть (Python, PyJWT):
import jwt
import datetime
from flask import Flask, jsonify, request
app = Flask(__name__)
SECRET_KEY = "your-super-secret-key"
# Условная "база" валидных refresh-токенов. В жизни — Redis или нормальная БД.
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 (опять на 15 минут)
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куках, чтобы никакой фронтендовый скрипт до неё не дотянулся. Вообще, идеально, если сервер её тебе только в такую куку и отдаёт. - Как отозвать? Это самое важное, блядь! Пользователь вышел (logout) — БАМ, удаляешь этот refresh token из белого списка (
VALID_REFRESH_TOKENS). Заподозрил, что аккаунт угнали — немедленно все его рефреши в пизду! Иначе злоумышленник будет до самого конца срока токена новые ключи себе генерировать, как ни в чём не бывало. Вот это будет пиздец, а не безопасность.