Comments 7
У вас неправильная логика работы с refresh-токеном, он должен быть одноразовым и содержать уникальный идентификатор, позволяющий различить сессии одного пользователя.
Новый refresh-токен выдаётся каждый раз при выдаче access-токена. Информация о выданном refresh-токене сохраняется в базе данных.
При попытке обновления access-токена проверяется не только то, что refresh-токен действителен, но и то, что он есть в базе (сессия пользователя не сброшена) и ещё не использовался.
Если refresh-токена нет в базе, то требуется аутентификация по логину/паролю.
Если refresh-токен уже использовался, то предполагается несанкционированный доступ и из базы удаляются все refresh-токены пользователя, что приводит к необходимости его повторной аутентификации во всех сессиях по завершению действия их access-токенов.
Если refresh-токен в порядке, то он отмечается в базе как использованный и выдаётся новая пара токенов (access + refresh).
Периодически база очищается от старых refresh-токенов, скажем с возрастом больше двойного срока действия.
Чел ещё асинхронку не освоил и полез jwt писать где обязательно потребуется воркеры и серверы синхронизировать.
А ещё обработкой refresh токенов и access токенов должны заниматься разные сервисы (authorization server и resource server)
Полностью согласен, что ротация refresh-токенов с хранением jti в БД — это правильная основа для продакшена.
Несколько практических дополнений:
Гонка запросов. При параллельных вызовах /refresh с одним токеном строгая одноразовость может привести к ложному логауту. Решается блокировкой в БД (SELECT FOR UPDATE SKIP LOCKED) и очередью на клиенте.
Нагрузка на БД. Ротация создаёт много операций записи. Активные токены лучше держать в Redis (с TTL), а PostgreSQL использовать для аудита и долгосрочной истории.
Управление сессиями. Добавление в таблицу refresh-токенов полей user_agent, ip, fingerprint позволяет пользователю видеть активные устройства и отзывать конкретные сессии.
Очистка. Redis сам удаляет истекшие записи. Для таблицы аудита нужен планировщик или партиционирование.
WebSocket. Если в приложении используются постоянные соединения, стоит продумать механизм переподключения с новым токеном без обрыва сессии.
Схема с ротацией хороша, но эти нюансы делают её готовой к реальным нагрузкам и сценариям использования.
Очередная нейростатья от вайбкодера?
На мой взгляд, habr должен обучать на примерах, поэтому работающий код расположен здесь ( https://github.com/longvalery/JWTFastAPI.git ) ветка master.
Я попробовал перевести логику на авторизации с учётом замечания Rsa97.
JWT авторизация в FastAPI: от теории до работающего кода