JWT (JSON Web Token) состоит из трёх логических частей, разделённых точками:
header.payload.signature
Каждая из этих частей кодируется в формате Base64Url и играет строго определённую роль в процессе формирования и проверки токена.
Заголовок JWT содержит метаданные о самом токене и алгоритме подписи.
Типичная структура:
{
"alg": "HS256",
"typ": "JWT"
}
algОпределяет алгоритм, используемый для создания подписи.
Наиболее распространённые варианты:
Выбор алгоритма влияет на всю криптографическую модель системы. Например, HS256 использует один секрет для подписи и проверки, тогда как RS256 разделяет приватный и публичный ключи.
typУказывает тип токена. В JWT всегда фиксированное значение:
"typ": "JWT"
Payload содержит утверждения (claims) — данные, которые передаются внутри токена.
Структура не фиксирована и может включать как стандартные, так и пользовательские поля.
Пример:
{
"sub": "user123",
"name": "Ivan Petrov",
"role": "admin",
"iat": 1710000000,
"exp": 1710003600
}
В payload можно добавлять произвольные данные:
{
"userId": 42,
"permissions": ["read", "write"],
"theme": "dark"
}
Payload не шифруется, а только кодируется. Это означает, что любые данные внутри JWT доступны для чтения после декодирования Base64Url. Поэтому хранить чувствительную информацию (пароли, секреты) внутри payload недопустимо.
Подпись обеспечивает целостность токена и подтверждает, что данные не были изменены.
Формирование подписи происходит на основе:
HMACSHA256(
base64Url(header) + "." + base64Url(payload),
secret
)
Для RSA-алгоритмов используется приватный ключ:
RSASHA256(
data,
privateKey
)
Подпись выполняет две ключевые функции:
Любая модификация даже одного символа в первых двух частях делает подпись недействительной.
Каждая часть JWT кодируется в Base64Url без padding
(=).
Финальная строка имеет вид:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiJ1c2VyMTIzIiwicm9sZSI6ImFkbWluIn0.
K8Q7f9p2h3mL9s8dKJH1aVx0cQeZ...
Библиотека Jsrsasign предоставляет инструменты для создания и проверки JWT без необходимости ручной реализации криптографических операций.
Пример создания токена:
const header = { alg: "HS256", typ: "JWT" };
const payload = {
sub: "user123",
role: "admin",
iat: KJUR.jws.IntDate.get("now"),
exp: KJUR.jws.IntDate.get("now + 1hour")
};
const secret = "my-secret-key";
const token = KJUR.jws.JWS.sign(
"HS256",
JSON.stringify(header),
JSON.stringify(payload),
secret
);
Здесь:
KJUR.jws.JWS.sign формирует JWT целикомДля декодирования используется функция:
const isValid = KJUR.jws.JWS.verifyJWT(token, secret, { alg: ["HS256"] });
const parsed = KJUR.jws.JWS.parse(token);
Результат parse содержит:
Пример доступа к данным:
console.log(parsed.headerObj);
console.log(parsed.payloadObj);
JWT имеет несколько ключевых характеристик, вытекающих из его структуры:
Payload содержит всю необходимую информацию для авторизации без обращения к базе данных.
Base64Url — это кодирование, а не защита. Любой может прочитать payload.
Signature гарантирует, что токен не был изменён после создания.
После создания JWT не может быть изменён без нарушения подписи. Это делает невозможным обновление payload без генерации нового токена.
Часто встречаются типичные проблемы:
none)exp, что приводит к вечным токенамПри валидации происходит последовательность:
exp,
nbf)Любое несоответствие приводит к отклонению токена.
JWT строго следует формату:
base64Url(header).base64Url(payload).base64Url(signature)
Любые дополнительные точки, пробелы или символы делают токен невалидным.
Размер токена зависит от:
Безопасность JWT полностью опирается на разделение структуры:
Эта модель делает JWT удобным для распределённых систем, где серверу не требуется хранить состояние сессий, но накладывает жёсткие ограничения на обращение с данными внутри токена.