Среды исполнения на базе Edge (Cloudflare Workers, Vercel Edge
Runtime) принципиально отличаются от классического Node.js. Основное
отличие заключается в том, что отсутствует доступ к большинству Node.js
встроенных модулей (crypto, fs,
net, stream в привычном виде). Вместо этого
используется стандартизированная Web Platform API, включая
WebCrypto API, Fetch API и Web Streams.
Библиотека jose изначально проектировалась с учётом этих
ограничений. В отличие от многих JWT-библиотек старого поколения, она не
полагается на Node.js crypto напрямую, а использует
унифицированный слой криптографии через crypto.subtle.
Ключевая особенность:
Это делает jose одной из стандартных библиотек для
работы с JWT, JWS, JWE в Edge Runtime.
Edge-окружения предоставляют объект crypto.subtle,
который реализует низкоуровневые криптографические операции:
jose полностью опирается на этот API.
Пример ключевых возможностей WebCrypto:
subtle.sign()subtle.verify()subtle.encrypt()subtle.decrypt()subtle.importKey()subtle.exportKey()Особенность Edge Runtime заключается в том, что все операции являются
асинхронными и возвращают Promise.
Внутри jose используется разделение на несколько
уровней:
Каждый слой не зависит от Node.js специфики, а использует абстракции поверх WebCrypto.
В Edge Runtime отсутствует fallback на Node.js crypto, поэтому поведение становится более предсказуемым и унифицированным между платформами.
Cloudflare Workers предоставляют полностью Web-совместимую среду. Это
означает, что jose работает без дополнительных
адаптеров.
Типичная особенность:
cryptoПример использования JWT в Cloudflare Workers:
import { jwtVerify, SignJWT } from 'jose'
const secret = new TextEncoder().encode('super-secret-key')
export default {
async fetch(request) {
const token = await new SignJWT({ userId: 123 })
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime('2h')
.sign(secret)
const { payload } = await jwtVerify(token, secret)
return new Response(JSON.stringify(payload), {
headers: { 'Content-Type': 'application/json' }
})
}
}
Важный момент: отсутствует необходимость в polyfill-ах или дополнительных криптографических библиотеках.
Vercel Edge Runtime также построен на Web Standards API, но имеет свои ограничения:
Bufferjose полностью совместим с этим окружением, так как не
требует Node-specific API.
Пример использования в Edge Function:
import { jwtVerify } from 'jose'
const secret = new TextEncoder().encode(process.env.JWT_SECRET)
export const config = {
runtime: 'edge'
}
export default async function handler(req) {
const token = req.headers.get('authorization')?.replace('Bearer ', '')
if (!token) {
return new Response('Unauthorized', { status: 401 })
}
const { payload } = await jwtVerify(token, secret)
return new Response(JSON.stringify(payload), {
headers: { 'Content-Type': 'application/json' }
})
}
В Edge Runtime доступен набор алгоритмов, поддерживаемых WebCrypto.
jose автоматически использует доступные реализации.
Наиболее распространённые алгоритмы:
Пример генерации и проверки RSA JWT:
import { generateKeyPair, SignJWT, jwtVerify } from 'jose'
const { privateKey, publicKey } = await generateKeyPair('RS256')
const token = await new SignJWT({ role: 'admin' })
.setProtectedHeader({ alg: 'RS256' })
.setExpirationTime('1h')
.sign(privateKey)
const verified = await jwtVerify(token, publicKey)
Edge Runtime особенно эффективно работает с JWK, так как ключи можно сериализовать и передавать между сервисами без бинарных форматов.
import { importJWK, jwtVerify } from 'jose'
const jwk = {
kty: 'oct',
k: 'c2VjcmV0a2V5',
alg: 'HS256'
}
const key = await importJWK(jwk, 'HS256')
const result = await jwtVerify(token, key)
Преимущество JWK в Edge-среде заключается в:
Edge-среды оптимизированы для минимальной задержки. jose
учитывает это за счёт:
Однако есть особенности:
В Edge Runtime критически важен размер бандла. jose
спроектирован с поддержкой tree-shaking:
Пример корректного импорта:
import { SignJWT } from 'jose'
Вместо:
import * as jose from 'jose'
Первый вариант позволяет сборщику исключить неиспользуемые части библиотеки.
Несмотря на совместимость, существуют системные ограничения:
jose адаптируется к этим условиям через:
В Edge Runtime поддерживается потоковая работа с зашифрованными данными через Web Streams API.
Это позволяет обрабатывать большие payload без загрузки всего объекта в память.
import { compactDecrypt } from 'jose'
const { plaintext } = await compactDecrypt(jwe, privateKey)
Хотя операция возвращает результат целиком, внутренняя обработка может использовать потоковые механизмы платформы.
Обе платформы следуют стандартам Web Platform, но различия проявляются в деталях:
jose абстрагирует эти различия, обеспечивая одинаковый
API слой.
В Edge Runtime ключи обычно хранятся:
HMAC пример:
const secret = new TextEncoder().encode(process.env.SECRET_KEY)
RSA пример через JWK:
const privateKey = await importJWK(JSON.parse(process.env.PRIVATE_JWK))
Edge Runtime часто применяется как слой:
jose становится стандартным инструментом для:
Это позволяет переносить часть security logic ближе к пользователю, снижая latency.