SignJWT — основной механизм создания JWT в библиотеке jose
SignJWT представляет собой высокоуровневый API для формирования и подписания JSON Web Token. Он инкапсулирует процесс подготовки payload, формирования защищённого заголовка и криптографической подписи, обеспечивая строгую совместимость со спецификацией JWT (RFC 7519) и JWS (RFC 7515).
Процесс создания токена через SignJWT всегда состоит из трёх логических частей:
В библиотеке jose эти этапы объединены в цепочку методов, что позволяет собирать токен декларативно.
Создание JWT начинается с инициализации объекта SignJWT и передачи payload:
import { SignJWT } from 'jose';
const jwt = await new SignJWT({ userId: 123 })
.setProtectedHeader({ alg: 'HS256' })
.sign(secret);
Здесь происходит следующее:
{ userId: 123 }HS256secretPayload представляет собой JSON-объект, который будет закодирован в JWT без шифрования (Base64URL encoding).
new SignJWT({
userId: 42,
role: 'admin'
})
Важно учитывать, что payload не является защищённым, поэтому не должен содержать чувствительные данные без дополнительного шифрования (например, JWE).
Protected header определяет параметры криптографической защиты:
.setProtectedHeader({
alg: 'HS256',
typ: 'JWT'
})
Основные алгоритмы, используемые в jose:
Выбор алгоритма напрямую влияет на тип ключа, который требуется для подписи.
JWT часто содержит стандартные поля (claims), которые задаются через методы SignJWT.
.setIssuedAt()
.setExpirationTime('2h')
iat — время создания токенаexp — время истеченияФорматы времени могут быть:
"2h", "10m",
"1d").setSubject('user:42')
.setIssuer('auth.service')
.setAudience('client.app')
.setJwtId('unique-id-123')
Назначение:
sub — субъект (обычно пользователь)iss — издатель токенаaud — получательjti — уникальный идентификаторSignJWT использует fluent API, где каждый метод возвращает текущий экземпляр:
const token = await new SignJWT({
userId: 7,
permissions: ['read', 'write']
})
.setProtectedHeader({
alg: 'HS256',
typ: 'JWT'
})
.setIssuer('auth-server')
.setAudience('web-client')
.setIssuedAt()
.setExpirationTime('15m')
.sign(secretKey);
Каждый вызов добавляет слой метаданных к будущему токену.
import { createSecretKey } from 'crypto';
const secretKey = createSecretKey(
Buffer.from('super-secret-key')
);
Используется с HS256 и родственными алгоритмами.
Для RSA:
import { importPKCS8 } from 'jose';
const privateKey = await importPKCS8(rsaPrivateKey, 'RS256');
Для JWK:
import { importJWK } from 'jose';
const key = await importJWK(jwk, 'ES256');
Метод .sign() выполняет несколько внутренних этапов:
header.payloadРезультат:
header.payload.signature
Все операции в SignJWT являются асинхронными, поскольку могут включать:
Поэтому использование await является обязательным.
Использование HS256 с RSA ключом приводит к ошибке подписи.
JWT без alg считается некорректным:
// ошибка
new SignJWT(payload).sign(key);
Установка exp в прошлом моментально инвалидирует
токен.
JWT может содержать произвольные данные:
new SignJWT({
scope: 'admin',
features: {
darkMode: true,
beta: false
}
})
Такие поля не интерпретируются библиотекой и передаются как есть.
.setProtectedHeader({
alg: 'ES256',
typ: 'JWT',
kid: 'key-id-1'
})
typ — тип токенаkid — идентификатор ключа (важно при ротации
ключей)JWT всегда кодируется в формате Base64URL без padding. jose гарантирует корректное соответствие стандарту, исключая ручные ошибки при кодировании.
После вызова .sign() объект SignJWT становится
одноразовым. Повторное использование экземпляра невозможно, что
предотвращает случайные утечки состояния между токенами.
SignJWT применяется в:
Каждый сценарий отличается набором claims и временем жизни токена.