Что делать с временем жизни JWT токена
Что проверяют
Понимаете ли вы компромисс: чем дольше живёт токен, тем дольше им пользуется тот, кто его украл, и тем меньше у вас способов это прервать. Заодно смотрят, знаете ли, что подписанный токен нельзя отозвать, не заведя состояние на сервере.
Как отвечать
Схема, которую от вас ждут: короткий access-токен и долгий refresh-токен. Access живёт минуты, проверяется полностью офлайн, по подписи и exp. Refresh живёт дни, хранится на сервере в виде хеша, и именно он даёт возможность прервать сессию: удалили запись, обновление больше не проходит.
Дальше важные детали:
- ротация: каждый обмен выдаёт новый refresh, старый гасится, а повторное предъявление погашенного это сигнал кражи, по которому рвётся вся цепочка сессий;
- проверять нужно не только
exp, но иnbf,iss,aud, а список алгоритмов вdecodeзадавать явно, иначе проверка подписи ослабляется; - небольшой допуск на расхождение часов между сервисами обязателен, иначе свежий токен местами будет считаться протухшим;
- в полезной нагрузке не место данным, которые меняются чаще, чем живёт токен: роль, отозванная минуту назад, останется в токене до
exp.
В Python это PyJWT, а время считается в UTC и с зоной: datetime.now(timezone.utc) + timedelta(minutes=15).
Где спотыкаются
Берут datetime.utcnow(). Он возвращает время без зоны и признан устаревшим, а смешение значений с зоной и без даёт токены, которые протухают мгновенно или живут лишние часы, смотря какая зона у сервера.
Возвращают из проверки строку вместо исключения. Вызывающий пишет условие по результату, непустая строка про истёкший токен истинна, и протухший токен пускают внутрь. Отказ проверки это исключение или явный признак, а не текст сообщения.
Обещают мгновенный отзыв и одновременно гордятся тем, что сервис не хранит состояния. Без списка отозванных по jti или отметки времени у пользователя выданный access работает до exp, и кнопка выхода со всех устройств гасит только обновление. Это и есть настоящая причина держать access коротким.