Карта / JWT и роли / Rotation, revoke

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
🎤 Закрыл тему, если можешь объяснить:
• зачем нужна ротация refresh token;
• как работает revoke и почему это «дорого» для stateless JWT (если дошёл до 2-го слоя).