Структура JWT: header, payload, signature

JWT представляет собой компактный токен, состоящий из трёх частей, разделённых точками:

header.payload.signature

Каждая часть кодируется в формате Base64URL, а затем объединяется в строку, используемую для передачи и проверки подлинности данных.


Header (заголовок) содержит метаданные о токене и алгоритме подписи. Это JSON-объект, который после сериализации и кодирования становится первой частью JWT.

Типичный пример:

{
  "alg": "HS256",
  "typ": "JWT"
}

Ключевые поля header:

  • alg — алгоритм подписи (например, HS256, RS256, ES256)
  • typ — тип токена, почти всегда “JWT”
  • kid (опционально) — идентификатор ключа, используется при работе с несколькими ключами

После формирования JSON он кодируется в Base64URL. Важно понимать, что header не защищён криптографически сам по себе — он лишь описывает, как должна проверяться подпись.


Payload

Payload содержит полезную нагрузку — данные, которые передаются внутри токена. Это также JSON-объект, который кодируется в Base64URL.

Пример payload:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "iat": 1710000000
}

Типы claims (заявлений):

  • Registered claims — стандартные поля:

    • iss (issuer) — кто выпустил токен
    • sub (subject) — идентификатор пользователя
    • exp (expiration time) — время истечения
    • iat (issued at) — время выпуска
    • aud (audience) — получатель токена
  • Public claims — пользовательские, но стандартизируемые через namespace

  • Private claims — произвольные данные, определённые приложением

Payload не шифруется, а лишь кодируется. Это означает, что его содержимое можно прочитать, но нельзя изменить без нарушения подписи.


Signature

Signature (подпись) обеспечивает целостность и подлинность JWT. Именно она гарантирует, что данные не были изменены после создания токена.

Формирование подписи происходит по следующему принципу:

signature = sign(
  base64Url(header) + "." + base64Url(payload),
  secret_or_private_key
)

Пример с HMAC (HS256)

При использовании симметричного алгоритма:

  • один секрет используется и для подписи, и для проверки
  • алгоритм: HMAC-SHA256

Пример с RSA (RS256)

При использовании асимметричного алгоритма:

  • приватный ключ используется для подписи
  • публичный ключ используется для проверки

Работа с JWT через библиотеку jose

Библиотека jose в JavaScript предоставляет современный API для работы с JWT и JOSE-стеком (JSON Web Signature, Encryption, Keys).

Создание JWT

Используется SignJWT:

import { SignJWT } from 'jose'

const secret = new TextEncoder().encode('secret-key')

const jwt = await new SignJWT({ userId: 123 })
  .setProtectedHeader({ alg: 'HS256' })
  .setIssuedAt()
  .setExpirationTime('2h')
  .sign(secret)

Здесь:

  • setProtectedHeader формирует header
  • payload передаётся в конструкторе
  • sign() создаёт signature

Проверка JWT

Для верификации используется jwtVerify:

import { jwtVerify } from 'jose'

const { payload, protectedHeader } = await jwtVerify(
  token,
  new TextEncoder().encode('secret-key')
)

Результат включает:

  • payload — декодированные данные
  • protectedHeader — header токена

Взаимосвязь header, payload и signature

JWT строится строго по цепочке:

  1. Формируется header (описание алгоритма)
  2. Формируется payload (данные)
  3. Оба объекта кодируются в Base64URL
  4. Из их соединения создаётся подпись
  5. Итоговый токен объединяет все три части

Любое изменение header или payload делает подпись недействительной, что позволяет обнаруживать подмену данных.


Base64URL кодирование

JWT использует модифицированную версию Base64:

  • + заменяется на -
  • / заменяется на _
  • убираются =

Это делает токен безопасным для использования в URL, заголовках HTTP и cookies.


Критические свойства структуры JWT

  • header и payload не защищены шифрованием
  • целостность обеспечивается только signature
  • изменение любого символа ломает подпись
  • JWT не требует хранения состояния на сервере

Типовые алгоритмы подписи

В контексте jose чаще всего используются:

  • HS256 — простой и быстрый, симметричный
  • RS256 — более безопасный, асимметричный
  • ES256 — на основе эллиптических кривых

Выбор алгоритма влияет на структуру ключей и модель безопасности системы.


Ошибки при работе со структурой JWT

  • использование слабого или общего секрета для HS256
  • игнорирование exp в payload
  • попытки доверять данным payload без проверки signature
  • неправильная обработка Base64URL при ручной реализации

JWT как структура остаётся фиксированной: три части, каждая из которых выполняет строго определённую роль — описание алгоритма, данные и криптографическое подтверждение целостности.