JWT: access и refresh токены
↑ 5.5 Аутентификация и доступ: Keycloak, SSO, ACL · ← Предыдущая · → Следующая
Зачем это на собесе
JWT спрашивают везде: структура, что проверять, зачем refresh и как хранить.
Объяснение
Подробно серверная сторона — JWT Bearer: валидация токена, claims, срок жизни. Клиентская перспектива:
JWT = header.payload.signature (Base64Url). Payload (claims: sub, iss, aud, exp, iat, роли) читается любым; подпись защищает от подделки, но не скрывает содержимое.
function parseJwt(t: string) {
const [, p] = t.split(".");
return JSON.parse(decodeURIComponent(escape(atob(p.replace(/-/g, "+").replace(/_/g, "/"))))); // только для чтения claims; проверка подписи — на сервере
}
const { exp } = parseJwt(token); const expiresInMs = exp * 1000 - Date.now();| Токен | Назначение | Срок | Хранение |
|---|---|---|---|
| Access | доступ к API (Authorization: Bearer) | 5–15 минут | в памяти (переменная/стор) |
| Refresh | получение нового access | часы–дни | HttpOnly cookie (или защищённо на сервере в BFF) |
| ID token (OIDC) | сведения о пользователе для клиента | короткий | не отправляют в API |
Обновление:
- Проактивно: по таймеру за 30–60 секунд до
exp(setTimeout,keycloak.updateToken(30)). - Реактивно: при 401 (см. интерсептор в Axios: инстансы и интерсепторы) с единым запросом обновления.
- Ротация refresh-токена: каждый refresh выдаёт новый; повторное использование старого → отзыв всей цепочки (защита от кражи).
- Выход: отзыв refresh на сервере (
logoutendpoint), очистка состояния и кэша Query.
Ограничения JWT:
- Невозможно «отозвать» access до
expбез списка отзыва/introspection — поэтому короткий срок. - Размер (заголовок
Authorizationв каждом запросе). - Не кладите чувствительные данные в payload.
- Проверка
expна клиенте — только для UX; сервер решает.
Проверка на сервере: подпись (JWKS), iss, aud, exp, nbf, алгоритм (запрет none).
Нюансы и подводные камни
- Смещение часов клиента: не полагайтесь на локальные часы точно (запас по времени).
- Несколько вкладок одновременно обновляют токен: синхронизируйте (BroadcastChannel/Web Locks).
- Потеря состояния при перезагрузке страницы: access в памяти → восстановление через refresh cookie (silent refresh).
- Токен в URL попадает в логи и историю.
Практика
- Реализуйте проактивное и реактивное обновление токена с единым запросом.
- Синхронизируйте обновление между вкладками.
- Опишите поведение при истёкшем refresh.
Вопросы с ответами
Зачем два токена?
Access — короткоживущий для запросов (минимизирует ущерб при краже), refresh — для получения нового access без повторного ввода пароля.
Можно ли доверять данным из JWT на клиенте?
Читать для UX можно, но проверка подписи и решения по доступу — на сервере.