Rotation, revoke
Проблема JWT: токен нельзя «инвалидировать» до истечения срока. Если access token утёк — ничего не поделать, пока он не истечёт. Если refresh token утёк — злоумышленник может бесконечно получать новые access tokens. Rotation и revoke — механизмы для контроля этих ситуаций.
Refresh Token Rotation — при каждом обновлении access token выдаётся новый refresh token, старый аннулируется:
Запрос: POST /auth/refresh { refresh_token: "OLD_RT" }
Ответ: { access_token: "NEW_AT", refresh_token: "NEW_RT" }
↑ OLD_RT теперь недействителен
Если злоумышленник пытается использовать украденный refresh token — он уже использован клиентом → сервер видит повторное использование → блокирует всю семью токенов (подозрение на компрометацию).
Revoke (отзыв токенов) — принудительная инвалидация токена до истечения срока. Для JWT это требует хранилища (Redis, БД):
// при logout или подозрительной активности
tokenBlacklist.add(tokenId, expiresAt); // jti (JWT ID) в blacklist
// при валидации каждого запроса
if (tokenBlacklist.contains(jti)) throw new UnauthorizedException();
Копнуть глубже
Почему это дорого. Проверка blacklist при каждом запросе = обращение к Redis/БД. Для stateless JWT это теряет основное преимущество — возможность проверять токен без обращения к хранилищу. Компромисс: blacklist только для refresh tokens (проверяется редко), access tokens остаются полностью stateless (короткий срок = приемлемый риск).
Семья токенов (Token Family). При обнаружении повторного использования refresh token (один и тот же RT используется дважды) → значит либо легитимный клиент, либо злоумышленник имеет копию. Безопаснее инвалидировать все refresh tokens пользователя, вынуждая заново залогиниться. Это идея «семьи» — связанные RT отслеживаются вместе.
jti claim в JWT — уникальный идентификатор конкретного токена (JWT ID). Используется для blacklist и для отслеживания семей токенов:
Jwts.builder()
.id(UUID.randomUUID().toString()) // добавляет claim "jti"
...
Практически: большинство продакшн-систем используют комбинацию:
- Access token: stateless JWT, 15 мин, не отзывается
- Refresh token: хранится в Redis с возможностью мгновенного отзыва
- Rotation при каждом использовании refresh token
• как работает revoke и почему это «дорого» для stateless JWT (если дошёл до 2-го слоя).