Стандарт JWS (JSON Web Signature) определяет несколько способов представления подписи:
header.payload.signature)Библиотека jose реализует все эти форматы. Flattened и General используются в случаях, когда требуется гибкость: дополнительные поля, несколько подписей, расширенные заголовки.
Формат Flattened применяется, когда подпись одна, но требуется JSON-структура вместо компактной строки.
{
"payload": "base64url...",
"protected": "base64url...",
"header": { ... },
"signature": "base64url..."
}
payload — закодированная нагрузкаprotected — защищённый заголовок (base64url JSON)header — необязательный незашищённый заголовокsignature — сама подписьimport { FlattenedSign } from 'jose'
const secret = new TextEncoder().encode('super-secret-key')
const payload = new TextEncoder().encode(JSON.stringify({
user: 'alice',
role: 'admin'
}))
const jws = await new FlattenedSign(payload)
.setProtectedHeader({ alg: 'HS256' })
.sign(secret)
new FlattenedSign(payload)
Uint8ArrayTextEncoder.setProtectedHeader({ alg: 'HS256' })
.setUnprotectedHeader({ kid: 'key-id-1' })
.sign(secret)
Формат General JSON Serialization используется, когда требуется подписать одно сообщение несколькими ключами.
{
"payload": "base64url...",
"signatures": [
{
"protected": "...",
"header": { ... },
"signature": "..."
},
{
"protected": "...",
"signature": "..."
}
]
}
import { GeneralSign } from 'jose'
const key1 = new TextEncoder().encode('secret-1')
const key2 = new TextEncoder().encode('secret-2')
const payload = new TextEncoder().encode('important data')
const jws = await new GeneralSign(payload)
.addSignature(key1)
.setProtectedHeader({ alg: 'HS256', kid: 'key1' })
.addSignature(key2)
.setProtectedHeader({ alg: 'HS256', kid: 'key2' })
.sign()
.addSignature(key)
.addSignature(key)
.setProtectedHeader({ alg: 'HS256' })
.setUnprotectedHeader({ kid: 'key-id' })
.sign()
Поддерживает несколько подписей
Каждая подпись имеет собственные заголовки
Все подписи относятся к одному payload
Используется для:
| Характеристика | FlattenedSign | GeneralSign |
|---|---|---|
| Количество подписей | 1 | 1+ |
| Формат | JSON | JSON |
| Сложность | Низкая | Выше |
| Использование | API, REST | Мультиподписи |
| Поддержка headers | Да | Да |
В обоих форматах доступны:
alg — алгоритм (обязательный)kid — идентификатор ключаtyp — тип токенаcty — тип содержимогоПример:
.setProtectedHeader({
alg: 'HS256',
typ: 'JWT',
kid: 'main-key'
})
Payload всегда должен быть:
Uint8Array
Пример:
const payload = new TextEncoder().encode('data')
Часто используемые:
Пример:
.setProtectedHeader({ alg: 'RS256' })
Flattened:
import { flattenedVerify } from 'jose'
const { payload } = await flattenedVerify(jws, key)
General:
import { generalVerify } from 'jose'
const { payload } = await generalVerify(jws, key)
alg в заголовке → ошибкаUint8Arrayalg{
"payload": "eyJ1c2VyIjoiYWxpY2UifQ",
"protected": "eyJhbGciOiJIUzI1NiJ9",
"signature": "abc123..."
}
{
"payload": "ZGF0YQ",
"signatures": [
{
"protected": "eyJhbGciOiJIUzI1NiJ9",
"signature": "sig1"
},
{
"protected": "eyJhbGciOiJIUzI1NiIsImtpZCI6IjIifQ",
"signature": "sig2"
}
]
}
API построен цепочкой вызовов (builder pattern)
Чёткое разделение этапов:
Унифицированная работа с ключами
Строгая типизация входных данных