Создание JWT с помощью KJUR.jws.JWS.sign

JWT (JSON Web Token) представляет собой компактный токен, используемый для передачи утверждений (claims) между участниками системы в виде JSON-структуры. В библиотеке Jsrsasign создание JWT реализуется через механизм JWS (JSON Web Signature), где основная функция формирования подписи и сборки токена — KJUR.jws.JWS.sign.

JWT состоит из трёх частей:

  • заголовок (header)
  • полезная нагрузка (payload)
  • подпись (signature)

Каждая часть кодируется в Base64URL и соединяется точками.


Перед формированием токена необходимо понимать, какие данные участвуют в подписи:

Header Содержит информацию о типе токена и алгоритме подписи:

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

Payload Содержит утверждения (claims):

{
  "sub": "1234567890",
  "name": "Ivan Ivanov",
  "admin": true,
  "iat": 1710000000
}

Подпись JWT в Jsrsasign

Основной метод формирования JWT:

KJUR.jws.JWS.sign(alg, header, payload, key)

Параметры:

  • alg — алгоритм подписи (HS256, HS384, HS512, RS256 и др.)
  • header — объект или JSON-строка заголовка
  • payload — объект или JSON-строка полезной нагрузки
  • key — секрет или приватный ключ (в зависимости от алгоритма)

Создание JWT с симметричным ключом (HS256)

Алгоритм HS256 использует общий секрет для подписи и проверки.

const header = {
  alg: "HS256",
  typ: "JWT"
};

const payload = {
  sub: "user123",
  name: "Ivan Ivanov",
  role: "admin",
  iat: Math.floor(Date.now() / 1000)
};

const secret = "super_secret_key";

const jwt = KJUR.jws.JWS.sign(
  "HS256",
  JSON.stringify(header),
  JSON.stringify(payload),
  secret
);

console.log(jwt);

Особенности HS256

При использовании HMAC:

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

Создание JWT с RSA (RS256)

Ассиметричный алгоритм RS256 использует пару ключей:

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

Приватный ключ должен быть в формате PEM.

const header = {
  alg: "RS256",
  typ: "JWT"
};

const payload = {
  sub: "user456",
  name: "Sergey Petrov",
  role: "user",
  iat: Math.floor(Date.now() / 1000)
};

const privateKey = `
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASC...
-----END PRIVATE KEY-----
`;

const jwt = KJUR.jws.JWS.sign(
  "RS256",
  JSON.stringify(header),
  JSON.stringify(payload),
  privateKey
);

console.log(jwt);

Особенности RS256

При использовании RSA:

  • подпись выполняется приватным ключом
  • проверка выполняется публичным ключом
  • секрет не передаётся между сторонами
  • повышенная безопасность для распределённых систем

Вариант передачи JSON без явной сериализации

Jsrsasign допускает передачу объектов напрямую:

const jwt = KJUR.jws.JWS.sign(
  "HS256",
  header,
  payload,
  secret
);

В этом случае библиотека автоматически сериализует структуру в JSON.


Использование стандартных claims

JWT часто содержит стандартные поля:

  • iss — издатель токена
  • sub — субъект
  • aud — аудитория
  • exp — время истечения
  • iat — время выпуска

Пример с ограничением срока жизни:

const payload = {
  sub: "user789",
  iss: "auth-server",
  exp: Math.floor(Date.now() / 1000) + 3600,
  iat: Math.floor(Date.now() / 1000)
};

Генерация токена с истечением срока

const jwt = KJUR.jws.JWS.sign(
  "HS256",
  {
    alg: "HS256",
    typ: "JWT"
  },
  {
    sub: "user999",
    exp: Math.floor(Date.now() / 1000) + 600,
    iat: Math.floor(Date.now() / 1000)
  },
  "secret123"
);

Алгоритмы, поддерживаемые KJUR.jws.JWS.sign

Чаще всего используются:

  • HS256 / HS384 / HS512
  • RS256 / RS384 / RS512
  • ES256 / ES384 / ES512

Выбор алгоритма влияет на модель безопасности:

  • HMAC — симметричная криптография
  • RSA и ECDSA — асимметричная криптография

Формирование токена вручную через sign

Внутри KJUR.jws.JWS.sign происходит:

  1. сериализация header в JSON
  2. сериализация payload в JSON
  3. Base64URL кодирование
  4. формирование строки header.payload
  5. вычисление подписи по алгоритму
  6. Base64URL кодирование подписи
  7. объединение всех частей

Частые ошибки при создании JWT

Неверный формат ключа RSA ключ должен быть в PEM-формате, включая заголовки:

-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----

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


Некорректный JSON Передача строки без корректной сериализации может привести к ошибкам подписи:

// потенциально проблемный вариант
payload: "{sub: user}"

Практическая структура генерации токена

Типичный процесс формирования JWT:

const header = { alg: "HS256", typ: "JWT" };

const payload = {
  sub: "1001",
  permissions: ["read", "write"],
  iat: Math.floor(Date.now() / 1000),
  exp: Math.floor(Date.now() / 1000) + 3600
};

const token = KJUR.jws.JWS.sign(
  "HS256",
  JSON.stringify(header),
  JSON.stringify(payload),
  "my_secret_key"
);

Контроль целостности JWT

Подпись обеспечивает:

  • защиту от изменения payload
  • подтверждение источника токена
  • целостность данных при передаче

Любое изменение payload после подписи делает токен недействительным при проверке.


Поведение при изменении данных

Если изменить payload вручную:

  • подпись перестаёт совпадать
  • валидация токена не проходит
  • система отклоняет токен как недостоверный

Особенности работы с временными метками

Поля iat и exp должны использовать Unix timestamp (секунды):

Math.floor(Date.now() / 1000)

Использование миллисекунд приводит к некорректной проверке срока действия.


Подпись сложных payload

Payload может содержать вложенные структуры:

const payload = {
  user: {
    id: 10,
    name: "Alex"
  },
  roles: ["admin", "editor"],
  session: {
    device: "mobile",
    ip: "127.0.0.1"
  }
};

Jsrsasign корректно сериализует такие объекты перед подписью.


Сравнение HS256 и RS256 при создании JWT

HS256:

  • быстрее
  • проще
  • требует общий секрет

RS256:

  • медленнее
  • безопаснее в распределённых системах
  • позволяет разделять подпись и проверку

Формирование минимального JWT

Минимально необходимый набор:

KJUR.jws.JWS.sign(
  "HS256",
  { alg: "HS256", typ: "JWT" },
  { sub: "1" },
  "key"
);