Edge-окружения накладывают жёсткие ограничения на выполнение
JavaScript-кода: нет полноценного Node.js API, отсутствует файловая
система, синхронные операции недоступны, а время и память ограничены
платформой. В таких условиях криптографические библиотеки должны
опираться не на Node.js crypto, а на Web Crypto API,
доступный в средах вроде Cloudflare Workers, Vercel Edge Runtime, Deno
Deploy и Bun.
Библиотека jose (JavaScript Object Signing and Encryption) изначально ориентирована на работу именно в таких условиях. Она реализует JWS (подпись), JWE (шифрование) и JWT (токены) поверх Web Crypto API без необходимости в нативных модулях Node.js.
Edge-окружения принципиально отличаются от серверного Node.js:
crypto в привычном видеВ результате любые решения для JWT и криптографии должны:
crypto.subtlejose соответствует этим требованиям и поэтому стал де-факто стандартом для Edge.
Библиотека построена вокруг модульного подхода:
jose/jwt — работа с JWTjose/jws — подпись и верификацияjose/jwe — шифрованиеjose/key — работа с ключамиjose/errors — обработка криптографических ошибокКлючевая особенность — отсутствие зависимости от Node.js API. Всё строится поверх:
SubtleCrypto (Web Crypto API)TextEncoder / TextDecoderHono — это ультра-лёгкий веб-фреймворк, ориентированный на Edge-окружения. Он идеально сочетается с jose, поскольку сам не требует Node.js runtime и работает поверх Fetch API.
Типичный сценарий — JWT-аутентификация через middleware.
import { Hono } from 'hono'
import { jwtVerify } from 'jose'
const app = new Hono()
const secret = new TextEncoder().encode('super-secret-key')
app.use('/api/*', async (c, next) => {
const authHeader = c.req.header('Authorization')
if (!authHeader) {
return c.json({ error: 'Missing Authorization header' }, 401)
}
const token = authHeader.replace('Bearer ', '')
try {
const { payload } = await jwtVerify(token, secret)
c.set('user', payload)
await next()
} catch (err) {
return c.json({ error: 'Invalid token' }, 401)
}
})
Этот код работает одинаково в Cloudflare Workers, Vercel Edge и Deno Deploy.
Создание токена через jose выполняется без синхронных операций:
import { SignJWT } from 'jose'
const secret = new TextEncoder().encode('super-secret-key')
const token = await new SignJWT({ userId: 123 })
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime('2h')
.sign(secret)
Здесь важен момент: даже криптографическая операция подписи полностью асинхронна и делегирована Web Crypto API.
import { jwtVerify } from 'jose'
const { payload, protectedHeader } = await jwtVerify(token, secret)
jwtVerify одновременно:
Edge-окружения часто используют публично/приватные ключи вместо симметричных секретов.
import { importSPKI, jwtVerify } from 'jose'
const publicKey = await importSPKI(
`-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----`,
'RS256'
)
const { payload } = await jwtVerify(token, publicKey)
Использование RSA или ECDSA в Edge важно для распределённых систем, где:
В Edge-архитектурах иногда требуется не только подпись, но и шифрование payload.
import { EncryptJWT } from 'jose'
const secret = new TextEncoder().encode('encryption-key')
const token = await new EncryptJWT({ role: 'admin' })
.setProtectedHeader({ alg: 'dir', enc: 'A256GCM' })
.setExpirationTime('1h')
.encrypt(secret)
Расшифровка:
import { jwtDecrypt } from 'jose'
const { payload } = await jwtDecrypt(token, secret)
jose полностью зависит от crypto.subtle, что накладывает
особенности:
Edge-окружения обычно поддерживают:
Hono позволяет централизовать проверку токенов и доступ к пользователю через контекст:
app.get('/profile', (c) => {
const user = c.get('user')
return c.json({ profile: user })
})
Это создаёт единый слой авторизации без привязки к Node.js middleware-моделям.
jose оптимизирован под ограничения Edge:
Однако существуют важные нюансы:
Использование Node.js crypto → в Edge это приводит к
runtime error
Передача строк вместо Uint8Array → jose требует явного encoding через TextEncoder
Неверный алгоритм подписи → strict validation в jwtVerify
Попытка синхронной генерации ключей → Edge не поддерживает sync crypto operations
В Edge-архитектурах с Hono и jose часто применяются следующие схемы:
Ключевые принципы:
jose поддерживает работу с несколькими ключами одновременно, что упрощает ротацию:
await jwtVerify(token, [key1, key2])
В Edge часто JWT хранится в HttpOnly cookies:
app.use(async (c, next) => {
const token = c.req.cookie('auth')
if (!token) return c.json({ error: 'Unauthorized' }, 401)
const { payload } = await jwtVerify(token, secret)
c.set('user', payload)
await next()
})
Это снижает риск XSS-атак по сравнению с localStorage.
При росте системы важно учитывать:
jose в этом контексте выступает как полностью stateless слой криптографии, что идеально соответствует модели Edge computing.