В библиотеке jose управление временем жизни токена
реализуется через стандартное JWT-claim поле exp
(expiration time). Оно определяет момент, после которого токен
становится недействительным. В процессе формирования JWT при помощи
SignJWT используется метод setExpirationTime,
который добавляет это значение в payload и корректно кодирует его в
соответствии со спецификацией JOSE.
Основная цель механизма — ограничить срок действия токена и минимизировать риск его повторного использования после компрометации.
expJWT содержит набор стандартных зарегистрированных claims. Среди них:
iat — время выпуска токенаnbf — время, с которого токен становится
действительнымexp — время истечения срока действияexp = , ;
Значение exp всегда выражается в Unix time (секунды с 1
января 1970 года UTC). При проверке токена библиотека сравнивает текущее
серверное время с этим значением.
Если текущее время больше или равно exp, токен считается
просроченным и отклоняется.
setExpirationTime в SignJWTВ jose создание подписанного JWT выполняется через
цепочку методов. Установка срока жизни реализуется методом:
import { SignJWT } from 'jose';
const token = await new SignJWT({ sub: 'user123' })
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime('2h')
.sign(secretKey);
Метод setExpirationTime принимает несколько
форматов:
Поддерживаются удобные относительные выражения:
'10s' — 10 секунд'5m' — 5 минут'2h' — 2 часа'1d' — 1 деньТакие значения интерпретируются относительно времени выпуска токена
(iat).
Можно передать Unix timestamp:
.setExpirationTime(Math.floor(Date.now() / 1000) + 3600)
Здесь срок действия фиксируется явно, без зависимости от
iat.
DateДопустим вариант с объектом Date:
.setExpirationTime(new Date('2026-01-01T00:00:00Z'))
Библиотека автоматически преобразует дату в Unix time.
exp и iatПри формировании токена важно понимать взаимосвязь между временем выпуска и временем истечения:
iat задаёт точку отсчётаexp вычисляется относительно неё или задаётся явноЕсли setIssuedAt() не указан, библиотека добавляет его
автоматически при необходимости расчёта относительных значений
времени.
При валидации JWT используется jwtVerify:
import { jwtVerify } from 'jose';
const { payload } = await jwtVerify(token, secretKey);
Если exp меньше текущего времени, будет выброшено
исключение JWTExpired.
В распределённых системах возможны расхождения времени между
серверами. Для компенсации используется параметр
clockTolerance:
await jwtVerify(token, secretKey, {
clockTolerance: '30s'
});
Это означает, что токен считается валидным ещё 30 секунд после истечения.
Срок действия зависит от типа токена и сценария использования:
Короткий срок жизни снижает риск злоупотребления:
Более длительный период:
expJWT требует Unix time в секундах:
// Ошибка
.setExpirationTime(Date.now() + 3600)
// Правильно
.setExpirationTime(Math.floor(Date.now() / 1000) + 3600)
iat и expЕсли токен формируется с неверной логикой времени, например:
exp меньше iatexp в прошломТакой токен сразу считается недействительным.
Длительные access-токены увеличивают риск компрометации. Даже при наличии HTTPS и защиты каналов передачи, украденный токен может быть использован до истечения срока.
Механизм setExpirationTime не зависит от алгоритма:
Во всех случаях exp обрабатывается одинаково, поскольку
относится к payload, а не к криптографии подписи.
Корректность проверки exp полностью зависит от
синхронизации времени:
На практике setExpirationTime часто используется
вместе:
setIssuedAt() — фиксирует момент созданияsetNotBefore() — задаёт задержку активацииrole,
scope)Пример:
const token = await new SignJWT({ role: 'admin' })
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setNotBefore('0s')
.setExpirationTime('15m')
.sign(secretKey);
Короткоживущие токены приводят к необходимости:
exp становится ключевым элементом стратегии
stateless-аутентификации, где сервер не хранит состояние сессии.
Перед отправкой токена имеет смысл проверять:
exp > iatОшибки на этом этапе невозможно исправить после выдачи токена, поскольку JWT неизменяем после подписи.