Что такое JWT: устройство, Bearer, срок действия

Из чего состоит токен, чем он отличается от Bearer и что делать с jwt expired

JWT (JSON Web Token) — это строка, в которой сервер записал данные о пользователе и подписал их. Состоит из трёх частей через точку: заголовок, данные (payload) и подпись. Первые две части — JSON в кодировке Base64url, их прочитает любой, а подпись не даёт изменить их незаметно. Формат описан в RFC 7519.

Из чего состоит JWT

Токен выглядит как длинная строка из букв, цифр, дефисов и подчёркиваний, в которой ровно две точки. Они делят её на три части:

  • заголовок (header) — JSON с типом токена typ и алгоритмом подписи alg, например {"alg":"HS256","typ":"JWT"};
  • данные (payload) — JSON с утверждениями (claims): кто пользователь, когда токен выпущен и когда истекает;
  • подпись (signature) — результат подписи первых двух частей секретным ключом.

Каждая из первых двух частей кодируется в Base64url: это Base64, где вместо + и / стоят - и _, а знаки = в конце отброшены. Поэтому все токены, где заголовок начинается с {"alg", начинаются с eyJhbGci. Подпись — это двоичные данные, тоже записанные в Base64url.

Токен, подписанный алгоритмом HS256 с секретом secret
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6ItCQ0L3QvdCwIiwiaWF0IjoxNzYyMDAwMDAwLCJleHAiOjE3NjIwMDM2MDB9.PmDjtytZgVisghmY7-WyncyX490QtocQf8C-33-HCS8

Подпись считают от строки «заголовок.данные». Сервер, получив токен, пересчитывает подпись своим ключом и сравнивает с той, что пришла. Если токен изменили хотя бы на один символ, подписи не совпадут. Для подписи используют HMAC (алгоритмы HS256, HS384, HS512, общий секрет на обе стороны) или пару ключей: закрытым ключом подписывает выпускающая сторона, а проверить может любой, у кого есть открытый ключ (RS256, PS256, ES256, EdDSA). Структура подписанных токенов описана в RFC 7515, список алгоритмов — в RFC 7518.

Что лежит в payload

Данные токена — обычный JSON, а набор полей определяет тот, кто его выпускает. Но у нескольких имён есть общий смысл (RFC 7519, раздел 4.1):

  • iss (issuer) — кто выпустил токен;
  • sub (subject) — о ком токен, обычно идентификатор пользователя;
  • aud (audience) — для кого токен предназначен;
  • exp (expiration time) — когда токен перестаёт действовать;
  • nbf (not before) — с какого момента токен действует;
  • iat (issued at) — когда токен выпущен;
  • jti — уникальный номер токена.

Время в exp, nbf и iat — Unix-время в секундах, то есть число секунд с 1 января 1970 года по UTC. Например, exp равное 1762003600 — это 1 ноября 2025 года, 13:26:40 по UTC. Это число легко перепутать с миллисекундами, которые в JavaScript отдаёт Date.now(): в токене должны быть именно секунды.

Данные из токена выше: действует один час
{
  "sub": "1234567890",
  "name": "Анна",
  "iat": 1762000000,
  "exp": 1762003600
}

JWT и Bearer: в чём разница

Эти слова часто путают, потому что встречаются вместе: Authorization: Bearer eyJhbGci…. На самом деле они про разное.

  • JWT — формат самого токена: как он устроен и подписан.
  • Bearer — способ передачи: схема авторизации в заголовке Authorization (RFC 6750). Слово значит «предъявитель»: кто предъявил токен, тот и получает доступ.

Bearer-токеном может быть и JWT, и обычная случайная строка (непрозрачный токен), которую сервер ищет у себя в базе. А JWT можно передать не только через Bearer, например в cookie или в параметре запроса. Поэтому «JWT или Bearer» не вопрос выбора: самая частая связка — JWT, переданный в схеме Bearer.

Раз токен действует у любого, кто его предъявил, его нужно беречь, как пароль: передавать только по HTTPS, не писать в логи и не показывать в адресной строке. При копировании из логов вместе с токеном часто захватывают слово Bearer : в нашем декодере его убирать не нужно.

Данные в токене не секретны

Самое частое заблуждение: раз токен подписан, значит, зашифрован. Нет. Подпись защищает от подделки, но не от чтения. Base64url — это не шифр, и содержимое payload читается без всякого ключа за секунду. Поэтому в токен нельзя класть пароли, номера документов, телефон и всё, что не должен видеть тот, у кого окажется токен. В нём место идентификатору, ролям и срокам.

Зашифрованный токен тоже существует: это JWE (RFC 7516), у него пять частей вместо трёх. Содержимое такого токена без ключа не прочитать. Обычные «JWT» в API почти всегда подписаны, но не зашифрованы.

Размер токена тоже имеет значение: он уходит с каждым запросом, а в cookie помещается около 4 килобайт. Лишних данных в нём лучше не держать.

jwt expired: что делать

jwt expired — сообщение библиотеки jsonwebtoken для Node.js (TokenExpiredError: jwt expired). Оно значит, что срок exp прошёл. В других библиотеках текст другой, смысл тот же: в PyJWT это ExpiredSignatureError: Signature has expired, в Java-библиотеке jjwt — ExpiredJwtException: JWT expired at ….

  • Вставьте токен в декодер: мы покажем, когда он истёк, например «Токен истёк 3 дня назад».
  • Если токен просрочен по-настоящему, получите новый: войдите заново или обновите его по refresh-токену, если ваша система его выдаёт. Просрочка — не сбой, а нормальное поведение: токены специально делают недолгими.
  • Если токен выпущен только что, но уже просрочен, проверьте время на серверах. Разница часов даёт ошибки и в обратную сторону: токен «из будущего» отклоняют обычно из-за nbf, иногда из-за iat. Многие библиотеки позволяют задать допуск на расхождение часов (leeway).
  • Если «срок» оказался в 1970 году или в далёком будущем, проверьте единицы: exp в миллисекундах вместо секунд даёт дату, которая наступит через десятки тысяч лет.

Срок проверяет библиотека на сервере при разборе токена. Отключать эту проверку (параметры вроде ignoreExpiration) ради «починки» ошибки не стоит: так просроченные токены начнут приниматься.

alg none и другие ловушки подписи

В заголовке можно указать "alg":"none". Такой токен не подписан вообще, его третья часть пустая, а запись заканчивается точкой. Стандарт допускает такие «незащищённые» токены (RFC 7519, раздел 6), но принимать их для входа нельзя: сочинить такой токен может кто угодно.

Токен с alg: none и ролью admin: подписи нет
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiIxMjM0NTY3ODkwIiwicm9sZSI6ImFkbWluIn0.

Когда-то в некоторых библиотеках атакующий мог заменить алгоритм в заголовке и получить принятый сервером токен. Правило для разработчика одно: алгоритм проверки нужно задавать на стороне сервера, а не брать из заголовка токена. Если же сервер ждёт именно RS256, токен с HS256 или none он должен отклонить. Декодер на parsetools предупредит об alg: none, об отсутствии exp и о сроке больше года.

Частые вопросы

Что такое JWT токен простыми словами

Это строка из трёх частей, в которой сервер записал данные о пользователе и подписал их. По подписи можно проверить, что данные не менялись. Читать содержимое можно без ключа.

Как расшифровать JWT токен

Первые две части — JSON в Base64url, поэтому их достаточно раскодировать. Ключ нужен только для проверки подписи. Вставьте токен в декодер на parsetools: он покажет заголовок, данные и сроки.

JWT и Bearer токен: в чём разница

JWT — формат токена, Bearer — способ его передачи в заголовке Authorization. Bearer-токеном может быть и JWT, и непрозрачная случайная строка.

Что значит jwt expired

У токена прошёл срок действия, поле exp. Получите новый токен, войдите заново или обновите его по refresh-токену.

Можно ли хранить в JWT пароль

Нет. Данные токена не зашифрованы, их читает любой, у кого есть токен. Храните только идентификатор, роли и сроки.

Безопасно ли вставлять токен в онлайн-декодер

Только если он разбирается в вашем браузере. На parsetools токен не отправляется на сервер и остаётся только во вкладке браузера, пока вы её не закроете; секрет и ключ не сохраняются нигде. В сервисы, которые отправляют токен на свой сервер, живые токены лучше не вставлять: проверить, что с ним происходит дальше, нельзя.

Инструменты по теме

Ещё в справке