В основе библиотеки jose лежит стандарт JSON Web Signature (JWS), описывающий способ создания цифровой подписи для произвольных данных. Один из наиболее распространённых форматов представления подписи — Compact Serialization, представляющий результат в виде строки из трёх частей:
BASE64URL(Protected Header) . BASE64URL(Payload) . BASE64URL(Signature)
Каждая часть кодируется с использованием Base64URL, что делает итоговую строку пригодной для передачи через HTTP-заголовки, URL и другие текстовые каналы.
Класс CompactSign используется для создания JWS в
компактном формате. Он инкапсулирует процесс:
Это основной инструмент для генерации подписанных токенов, включая JWT.
import { CompactSign } from 'jose'
Создание подписи начинается с передачи данных в виде
Uint8Array:
const encoder = new TextEncoder()
const payload = encoder.encode('example payload')
const signer = new CompactSign(payload)
На этом этапе объект содержит только полезную нагрузку. Следующий шаг — указание защищённого заголовка.
Protected Header — это JSON-объект, который:
Пример:
signer.setProtectedHeader({
alg: 'HS256',
typ: 'JWT'
})
Ключевые параметры:
JWT)Библиотека jose поддерживает множество алгоритмов:
Симметричные:
Асимметричные:
Выбор алгоритма напрямую влияет на тип используемого ключа.
const secret = encoder.encode('super-secret-key')
const jws = await new CompactSign(payload)
.setProtectedHeader({ alg: 'HS256' })
.sign(secret)
console.log(jws)
Результат — строка вида:
eyJhbGciOiJIUzI1NiJ9.<payload>.<signature>
Для асимметричных алгоритмов используется приватный ключ:
import { generateKeyPair } from 'jose'
const { privateKey } = await generateKeyPair('RS256')
const jws = await new CompactSign(payload)
.setProtectedHeader({ alg: 'RS256' })
.sign(privateKey)
Процесс можно разбить на этапы:
Сериализация заголовка
Сериализация payload
Формирование signing input
BASE64URL(header) + '.' + BASE64URL(payload)Вычисление подписи
CompactSign принимает только бинарные данные
(Uint8Array). Это означает:
TextEncoderconst data = { user: 'alice', admin: true }
const payload = encoder.encode(JSON.stringify(data))
Дополнительные параметры позволяют расширить поведение:
.setProtectedHeader({
alg: 'RS256',
kid: 'key-id-123',
typ: 'JWT'
})
Важно: заголовок, установленный через
setProtectedHeader, полностью защищён подписью. Любое
изменение делает подпись недействительной.
Метод .sign() всегда асинхронный:
const jws = await signer.sign(key)
Причины:
Хотя CompactSign — низкоуровневый инструмент, он может
использоваться для создания JWT вручную:
const payload = encoder.encode(JSON.stringify({
sub: '1234567890',
name: 'John Doe',
iat: Math.floor(Date.now() / 1000)
}))
const jwt = await new CompactSign(payload)
.setProtectedHeader({ alg: 'HS256', typ: 'JWT' })
.sign(secret)
Основные причины ошибок:
alg в заголовкеПример обработки:
try {
const token = await signer.sign(key)
} catch (err) {
console.error('Ошибка подписи:', err)
}
Ключевые аспекты:
Особенно важно:
alg: "none"CompactSign оптимизирован для:
Однако:
Compact формат:
Альтернативы:
CompactSign используется именно тогда, когда важны
компактность и совместимость.
Uint8Array)CompactSignconst jws = await new CompactSign(payload)
.setProtectedHeader({ alg: 'HS256' })
.sign(secret)
Такой подход обеспечивает строгую, стандартизированную и криптографически безопасную подпись данных в JavaScript.