В криптографических сценариях WebCrypto API публичные ключи часто представляются в виде стандарта SPKI (Subject Public Key Info). Этот формат используется для сериализации публичных ключей в бинарное представление, совместимое с X.509 инфраструктурой.
В библиотеке jose экспорт SPKI выполняется через функцию
exportSPKI.
Основная задача exportSPKI — преобразовать объект
CryptoKey публичного ключа в строку PEM:
import { generateKeyPair, exportSPKI } from 'jose'
const { publicKey } = await generateKeyPair('RS256')
const spki = await exportSPKI(publicKey)
console.log(spki)
Результатом будет строка вида:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqh...
-----END PUBLIC KEY-----
SPKI особенно часто применяется в сценариях JWT-валидации, где публичный ключ передаётся в виде сертификата или конфигурационного файла.
Для приватных ключей используется стандарт PKCS8 (Private-Key Information Syntax Specification). Он описывает структуру хранения приватного ключа независимо от алгоритма.
В jose экспорт осуществляется функцией exportPKCS8.
import { generateKeyPair, exportPKCS8 } from 'jose'
const { privateKey } = await generateKeyPair('RS256')
const pkcs8 = await exportPKCS8(privateKey)
console.log(pkcs8)
Выходные данные:
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqh...
-----END PRIVATE KEY-----
PKCS8 часто используется при сохранении ключей в файлы или при передаче между backend-сервисами.
Формат JWK (JSON Web Key) представляет ключ как JSON-структуру. Это основной формат в экосистеме JWT/JWS/JWE.
В jose экспорт выполняется функцией exportJWK.
import { generateKeyPair, exportJWK } from 'jose'
const { publicKey } = await generateKeyPair('ES256')
const jwk = await exportJWK(publicKey)
console.log(jwk)
Пример результата:
{
"kty": "EC",
"crv": "P-256",
"x": "f83OJ3D2xF4...",
"y": "x_FEzRu9..."
}
import { exportSPKI } from 'jose'
const publicKeyPEM = await exportSPKI(publicKey)
// отправка в другой сервис
import { exportPKCS8 } from 'jose'
import { writeFileSync } from 'node:fs'
const privateKeyPEM = await exportPKCS8(privateKey)
writeFileSync('private.pem', privateKeyPEM)
import { exportJWK } from 'jose'
const jwk = await exportJWK(publicKey)
const jwks = {
keys: [jwk]
}
console.log(JSON.stringify(jwks, null, 2))
Все операции экспорта возвращают Promise, поскольку
используют WebCrypto API:
const key = await exportJWK(publicKey)
exportSPKI → только CryptoKey publicexportPKCS8 → только CryptoKey
privateexportJWK → оба типаПопытка передать неправильный тип приводит к ошибке выполнения.
Экспорт в jose часто используется вместе с импортом:
exportSPKI ↔︎ importSPKIexportPKCS8 ↔︎ importPKCS8exportJWK ↔︎ importJWKЭто позволяет строить полный цикл:
PEM (SPKI/PKCS8) удобен для файловой системы и инфраструктуры.
JWK удобен для:
При использовании exportPKCS8 или exportJWK
для приватных ключей необходимо учитывать:
Экспортируемый формат зависит от типа ключа:
Некоторые алгоритмы лучше работают с JWK (например EdDSA), поскольку PEM-эквиваленты ограничены.
При построении системы аутентификации часто используется JWKS:
const jwk = await exportJWK(publicKey)
const jwks = {
keys: [jwk]
}
Такой набор публикуется по endpoint:
/.well-known/jwks.json
Клиенты автоматически получают публичные ключи для проверки JWT.
Частые проблемы при работе с функциями экспорта:
TypeError: Key is not extractable
Причина: ключ создан без флага extractable: true.
Некоторые ключи нельзя экспортировать в определённые форматы из-за ограничений WebCrypto.
Ключ создан как non-exportable:
crypto.subtle.generateKey(
{
name: "RSASSA-PKCS1-v1_5",
modulusLength: 2048,
hash: "SHA-256"
},
false, // <- extractable = false
["sign", "verify"]
)
Экспорт ключей в jose напрямую влияет на архитектуру систем:
Эти три формата формируют основу совместимости между различными криптосистемами и сервисами идентификации.