Каждый раз, когда пользователь входит в SaaS-приложение, генерируется
токен аутентификации
, который передаётся браузеру или мобильному приложению. Внутри этого токена тикает скрытый таймер. Поле
срока действия JWT
, хранящееся как обычный Unix-timestamp, сообщает каждому серверу, который читает токен, до какого момента ему доверять. Ошибись в этом значении даже на несколько секунд - и пользователи либо будут выброшены из сессии раньше времени, либо, что хуже, продолжат работать с просроченными правами доступа дольше, чем допускает политика безопасности. Понимание того, как работают клеймы
JSON web token
- особенно
exp
и
iat
- одна из самых практичных вещей, которую команда разработки SaaS может сделать для укрепления аутентификации без лишних сложностей.
Ключевые выводы:
-
Клеймы
expиiatв JWT JSON web token всегда являются Unix-timestamp в целых секундах, а не миллисекундах. - Расхождение часов между серверами может незаметно аннулировать токены или продлевать сессии сверх допустимого - стандартное решение - окно допуска в 60 секунд.
- Слишком большой срок действия токена повышает риск взлома; слишком маленький портит пользовательский опыт. Конкретная формула поможет выбрать правильное значение.
- Декодировать и проверить любой timestamp из JSON web token в секундах можно с помощью конвертера Unix epoch - без каких-либо библиотек.
Содержание
- Что такое JWT и почему внутри него живут временные метки
-
Клеймы
expиiat: подробное объяснение - Практический пример: декодирование реальных временных меток токена
- Расхождение часов: скрытый убийца токенов
- Как выбрать правильный срок действия токена для SaaS-продукта
- Конкретные шаги для безопасной реализации срока действия JWT
- Заключение
Что такое JWT и почему внутри него живут временные метки
JSON web token - это компактный, безопасный для URL токен, состоящий из трёх частей в кодировке Base64, разделённых точками: заголовок, payload и подпись. Именно в payload хранятся данные, чувствительные ко времени. Поскольку JWT работают в stateless-режиме, сервер не обращается к базе данных для проверки сессии. Вместо этого он читает клеймы, встроенные в payload, и доверяет криптографической подписи. Такой подход быстр и масштабируем, но создаёт реальное ограничение: после выпуска токена сервер не может его «удалить». Единственный надёжный способ ограничить срок жизни токена - встроить временную метку истечения непосредственно в него.
Именно поэтому время - а точнее, Unix epoch time - является центральным элементом безопасности JWT. Спецификация RFC 7519 , определяющая JWT, требует, чтобы временные клеймы выражались как значения «NumericDate» - то есть количество секунд с 1 января 1970 года UTC. Никаких часовых поясов. Никакого форматирования. Просто целое число, которое любой сервер в любой точке мира может сравнить со своими часами.
Клеймы
exp
и
iat
: подробное объяснение
Спецификация JWT определяет несколько зарегистрированных клеймов. Для управления жизненным циклом токена наиболее важны два:
-
exp(Expiration Time - время истечения): Временная метка, после которой токен не должен приниматься. Серверы обязаны отклонять любой токен, у которого текущее время равно этому значению или превышает его. Это и есть основной механизм срока действия JWT. -
iat(Issued At - время выпуска): Временная метка создания токена. Клейм iat не проверяется по умолчанию, но крайне полезен. Он позволяет вычислить возраст токена, независимо отexpприменять политику максимального возраста и обнаруживать токены, выпущенные подозрительно давно.
Третий клейм,
nbf
(Not Before - не раньше), определяет самый ранний момент, с которого токен считается действительным. Он используется реже, но следует тому же формату Unix-timestamp.
Все три значения являются целыми числами. Если твоя система генерирует их в миллисекундах (распространённая ошибка при использовании
Date.now()
в JavaScript), результирующее число окажется примерно в 1000 раз больше ожидаемого. Сервер, сравнивающий
exp
с текущим временем в секундах, увидит токен, который якобы истекает в 33658 году, и никогда его не отклонит. Это реальный баг, встречавшийся в продакшне у нескольких SaaS-команд.
Практический пример: декодирование реальных временных меток токена
Предположим, сервис аутентификации выпускает следующий JWT payload после входа пользователя в 10:00 UTC 1 июля 2025 года:
{
"sub": "user_8821",
"iat": 1751364000,
"exp": 1751367600,
"role": "admin"
}
Разберём, что означают эти числа:
| Клейм | Unix Timestamp | Читаемый формат (UTC) | Значение |
|---|---|---|---|
iat
|
1751364000 | 2025-07-01 10:00:00 | Токен выпущен в этот момент |
exp
|
1751367600 | 2025-07-01 11:00:00 | Токен истекает ровно через 1 час |
Разница составляет ровно 3600 секунд, то есть один час. Любой сервер, получивший этот токен после 11:00:00 UTC, обязан его отклонить. Проверить это вручную просто: вычти
iat
из
exp
: 1751367600 - 1751364000 = 3600 секунд. Читаемый эквивалент любого из этих значений можно мгновенно получить с помощью конвертера Unix-timestamp - это именно та быстрая проверка, которая помогает поймать ошибку миллисекунды/секунды до того, как она попадёт в продакшн.
Подробнее о том, как базы данных должны хранить эти значения, читай в нашем руководстве по
Unix-timestamp в базах данных - тот же целочисленный формат применяется как при хранении
exp
в токене, так и в таблице журнала аудита.
Расхождение часов: скрытый убийца токенов
Вот реальная проблема, которая застаёт команды врасплох. В распределённой системе сервер аутентификации и API-сервер - это разные машины. Их системные часы синхронизируются через NTP, но никогда не идут идеально точно. Расхождение в 30-90 секунд - норма для облачных окружений.
Рассмотрим сценарий: токен с
exp = 1751367600
проверяется API-сервером, чьи часы показывают 1751367610 - всего на 10 секунд позже истечения. Токен отклоняется. Пользователь получает ошибку 401. С его точки зрения, он только что вошёл в систему, и приложение сломалось.
Стандартное решение - добавить допуск на расхождение часов в логику валидации. Большинство JWT-библиотек поддерживают параметр leeway. Значение в 60 секунд широко принято и упоминается в спецификации OpenID Connect Core. Установи его, задокументируй и убедись, что все сервисы в твоём стеке используют одно и то же значение.
Практическое правило:
Добавляй допуск в 60 секунд при проверке
exp
. Никогда не добавляй допуск к проверкам
iat
- это позволило бы принимать токены, выпущенные в будущем, что является явным признаком атаки повторного воспроизведения (replay attack).
Как выбрать правильный срок действия токена для SaaS-продукта
Оптимальный срок действия токена зависит от чувствительности приложения и ожидаемого поведения сессий. Вот практический фреймворк:
- Приложения с высоким уровнем чувствительности (банкинг, медицина, панели администратора): 15-30 минут для access-токенов. Используй refresh-токены для тихого обновления сессий.
- Стандартные SaaS-приложения (управление проектами, CRM, аналитика): 1-8 часов. Ориентируйся на типичную длину рабочей сессии.
- API с низким риском или только для чтения: До 24 часов, но сочетай с ротацией токенов при чувствительных операциях.
- Сервисные токены для взаимодействия машина-машина: Могут быть долгосрочными (дни или недели), но должны иметь узкие права и ротироваться по расписанию.
Полезная формула для вычисления значения
exp
в момент выпуска токена:
// Node.js example
const iat = Math.floor(Date.now() / 1000); // current time in seconds
const ttl = 3600; // time-to-live: 1 hour in seconds
const exp = iat + ttl;
const payload = {
sub: userId,
iat: iat,
exp: exp
};
Обрати внимание на явное деление на 1000 для перевода миллисекунд в секунды. Эта одна строка предотвращает самую распространённую ошибку с JWT-timestamp в JavaScript-приложениях.
Конкретные шаги для безопасной реализации срока действия JWT
Вот конкретный чеклист, который можно применить к любой системе аутентификации SaaS прямо сейчас:
-
Всегда включай оба клейма -
iatиexp. Клеймiatтехнически необязателен, но он даёт тебе журнал аудита и позволяет применять политику максимального возраста независимо от срока истечения. -
Проверяй формат timestamp перед деплоем.
Декодируй токен и убедись, что
exp- это 10-значное целое число. Если в нём 13 цифр - в код проникли миллисекунды. - Установи допуск на расхождение часов в 60 секунд в своём middleware валидации. Применяй его единообразно во всех сервисах, которые потребляют токены аутентификации.
- Используй краткосрочные access-токены вместе с refresh-токенами. Access-токен на 15 минут в паре с refresh-токеном на 7 дней значительно безопаснее, чем один access-токен на 7 дней, потому что refresh-токен можно отозвать на стороне сервера.
-
Логируй значение
iatпри каждом аутентифицированном запросе. Это позволяет обнаруживать аномалии - например, использование одного и того же токена из двух разных географических регионов одновременно. -
Тестируй истечение срока действия на стейджинге с ускоренным временем.
Замокай часы так, чтобы они перескочили значение
exp, и убедись, что приложение корректно обрабатывает ошибку 401, а не падает или зацикливается.
Если тебе нужно быстро перевести сырое значение
exp
из токена в читаемую дату или проверить, какой timestamp задать для нужной длительности, воспользуйся
конвертером epoch на нашей главной странице
- он мгновенно работает в обоих направлениях без написания кода.
Заключение
Срок действия JWT - не сложная концепция, но именно здесь небольшие ошибки создают серьёзные бреши в безопасности. Клеймы
exp
и
iat
- это просто целые числа, Unix-timestamp в секундах от начала эпохи. Эта простота и есть их сила: любой сервер, на любом языке, на любой платформе может сравнить два числа без неоднозначности. Настоящее мастерство - в правильном применении: выбрать разумный
срок действия токена
, обработать расхождение часов с помощью окна допуска и поймать ошибку миллисекунды/секунды до того, как она уйдёт в продакшн. Внедри эти практики в свой пайплайн аутентификации - и реализация
JSON web token
будет одновременно безопасной и удобной в поддержке.
Проверяй JWT-timestamp мгновенно - без написания кода
Вставь любой Unix-timestamp из JWT payload и преобразуй его в читаемую дату одним кликом. Лови ошибки миллисекунды/секунды до того, как они попадут в продакшн.
Попробовать бесплатный инструмент →
exp
(Expiration Time) - это Unix-timestamp, после которого токен недействителен и должен быть отклонён.
iat
(Issued At) - это timestamp момента создания токена. Оба значения являются целыми числами в секундах. Клейм
iat
необязателен, но полезен для аудита и применения политик максимального возраста токена.
Unix-timestamp - это целые числа, не зависящие от часового пояса, что исключает неоднозначность на всех серверах и во всех регионах. Форматированные строки дат вроде «2025-07-01T10:00:00» могут быть неверно интерпретированы в зависимости от локали или настроек часового пояса. К тому же сравнение целых чисел быстрее и менее подвержено ошибкам, чем парсинг строк в высоконагруженных системах аутентификации.
Долгоживущий токен остаётся действительным, даже если аккаунт пользователя был скомпрометирован или его права изменились. Поскольку JWT работают в stateless-режиме, сервер не может отозвать их в середине срока действия. Если злоумышленник похитит токен со сроком действия 30 дней, у него будет 30 дней доступа. Короткие окна истечения в сочетании с refresh-токенами существенно сокращают этот риск.
В JavaScript всегда используй
Math.floor(Date.now() / 1000)
при генерации значений
iat
или
exp
. Сырой
Date.now()
возвращает миллисекунды. Деление на 1000 переводит их в целое число секунд, которое требует спецификация JWT. Проверить правильность просто: timestamp должен быть 10-значным числом, а не 13-значным.
Расхождение часов (clock skew) - это небольшая разница между системными часами двух серверов в распределённой системе. Даже разница в 30 секунд может привести к отклонению действительного токена, если часы проверяющего сервера немного спешат. Стандартное решение - настроить допуск в 60 секунд в JWT-библиотеке валидации, чтобы компенсировать нормальный дрейф NTP.