Что такое JWT-токен и как его расшифровать
Что такое JWT-токен и как его расшифровать
ДБ
Дмитрий Борисенко
Открываете DevTools, смотрите заголовок Authorization в запросе — а там строка
из трёх частей через точку, вида eyJhbGciOiJIUzI1NiIs.... Это JWT
(JSON Web Token) — формат, на котором держится авторизация в большинстве
современных API. Выглядит он как нечитаемая каша, но на самом деле — просто
JSON, обёрнутый в Base64URL. Разберём, что внутри и почему это не то же самое,
что шифрование.
Расшифровать (точнее — декодировать) готовый токен и посмотреть, что в нём лежит, можно прямо в браузере в JWT-декодере — вставляете строку целиком, заголовок и payload раскладываются в читаемый JSON без единого запроса на сервер.
Из чего состоит JWT
Токен — это всегда три части, разделённые точками:
- Header — метаданные: каким алгоритмом подписан токен (
alg) и его тип (typ: JWT). - Payload — сами данные: ID пользователя, роль, время выдачи и истечения. Их называют claims (утверждениями).
- Signature — подпись, которая гарантирует, что header и payload не подменили после выдачи токена.
Header и payload закодированы в Base64URL — это тот же Base64, но символы
+// заменены на -/_, а завершающие = обычно опущены, чтобы строку
можно было без проблем вставлять в URL и заголовки. Раскодировать каждую часть
вручную можно и в обычном Base64-кодировщике,
переключив его в URL-safe режим — но JWT-декодер делает это сразу для всех
трёх частей и подсвечивает результат как JSON.
Почему это не шифрование
Здесь кроется главная путаница: Base64 — это кодирование, а не шифрование. У
кодирования нет ключа, и раскодировать его может кто угодно за долю секунды —
ровно то же самое проделывает atob() в консоли браузера. Подставьте любой
чужой JWT (например, из примера выше) в декодер — увидите его payload
целиком, без всякого пароля.
Из этого следует практическое правило: в payload JWT нельзя класть ничего, что не должно быть публично читаемым — ни пароли, ни номера карт, ни личные данные, которые не предназначены для клиента. Токен защищает не содержимое, а целостность: подпись не даёт незаметно подменить данные внутри, но не скрывает их.
Что проверяет подпись — и чего она не проверяет
Подпись считается сервером по формуле вида
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
— и добавляется третьей частью. Если сервер получает токен обратно, он
пересчитывает подпись с тем же секретным ключом и сверяет её с той, что
пришла в токене.
- Совпало → header и payload точно не менялись с момента выдачи.
- Не совпало → токен подделан или подписан другим ключом — сервер его отклоняет.
Ключевой момент: для этой проверки нужен секретный (или приватный) ключ, которого нет ни у браузера, ни у любого онлайн-декодера. Поэтому JWT-декодер показывает header и payload, но честно не пытается подтвердить, что подпись настоящая — сама постановка вопроса «мне нужно на глаз понять, что лежит в токене» не требует ключа, а вопрос «валиден ли этот токен» может ответить только тот, кто его выдал.
Алгоритмы: симметричные и асимметричные
В поле alg заголовка чаще всего встречаются два семейства:
- HS256 (HMAC + SHA-256). Один и тот же секретный ключ и подписывает токен, и проверяет подпись. Проще в настройке, но ключ должен знать каждый сервис, который проверяет токены.
- RS256 (RSA + SHA-256). Токен подписывается приватным ключом, а проверяется публичным. Приватный ключ остаётся у одного сервиса-эмитента (например, Auth0 или собственного auth-сервера), а публичный можно спокойно раздать всем, кто должен проверять токены — подделать подпись без приватного ключа они всё равно не смогут.
Для микросервисной архитектуры RS256 обычно удобнее: сервисам, которые только проверяют токены, не нужно доверять секрет, которым можно подписать новый.
Частые поля payload (claims)
Часть полей в payload — стандартные, определены спецификацией RFC 7519, и большинство библиотек их понимают из коробки:
| Claim | Значение | Пример |
|---|---|---|
sub |
Subject — кому выдан токен | ID пользователя |
iss |
Issuer — кто выдал токен | auth.example.com |
aud |
Audience — для какого сервиса | api.example.com |
exp |
Expiration — когда токен истекает | Unix-время в секундах |
iat |
Issued At — когда токен выдан | Unix-время в секундах |
jti |
JWT ID — уникальный ID токена | UUID |
exp и iat хранятся как Unix-время (секунды с 1 января 1970 года), а не как
строка с датой — поэтому в сыром JSON вместо 2026-08-02 вы увидите что-то
вроде 1785715200. Декодер переводит такие поля в читаемую дату
автоматически; остальные claims — уже произвольные, их состав задаёт
конкретное приложение (роль, права, тариф пользователя).
Что делать, если декодирование не получилось
- Токен не разбивается на три части. Проверьте, что скопировали строку целиком — обрезанный при копировании конец обычно и есть причина.
- Ошибка в JSON после декодирования. Значит, в токен закралась опечатка или лишний символ — токены не редактируют вручную, их перевыпускает сервер.
- Это вообще не JWT. Строка из одной части без точек — просто Base64 или случайный токен доступа другого формата (например, opaque-токен), а не JWT.
Не вставляйте боевые токены с чужими данными
Декодирование в браузере полностью локальное — токен никуда не отправляется. Но это не повод копировать в любой онлайн-инструмент токен из продакшена, где в payload может лежать чужой email, роль или внутренний ID: сама строка уже содержит эти данные в открытом виде, декодер лишь делает их читаемыми. Для отладки формата удобнее использовать тестовый токен, который вы сгенерировали сами, а не тот, что система выдала реальному пользователю.
JWT декодер
Декодируйте и анализируйте JSON Web Token без ключа
Попробовать
Коротко
- JWT — это JSON, закодированный в Base64URL, а не зашифрованный: раскодировать header и payload может кто угодно без ключа.
- Подпись (третья часть) защищает данные от подмены, но не от прочтения — её проверка требует секретного или приватного ключа, которого нет у клиента.
- HS256 использует один общий секрет для подписи и проверки, RS256 — приватный ключ для подписи и публичный для проверки.
expиiatв payload — это Unix-время в секундах, а не строка с датой.- Раз содержимое токена читается открыто, в payload не должно быть данных, которые не предназначены для клиента.



