JWT (JSON Web Token) используется для передачи проверяемых данных между клиентом и сервером без хранения состояния на сервере. В контексте Fresh — фреймворка для Deno с серверным рендерингом и островной архитектурой — JWT чаще всего применяется для аутентификации и авторизации пользователей в HTTP-запросах.
Fresh по умолчанию не навязывает систему аутентификации. JWT хорошо вписывается в философию минимализма: токен формируется, подписывается, передаётся клиенту и проверяется при каждом запросе без обращения к базе сессий.
JWT состоит из трёх частей, разделённых точками:
header.payload.signature
Header Содержит метаданные токена:
{
"alg": "HS256",
"typ": "JWT"
}
Payload Хранит полезные данные (claims):
{
"sub": "user_id_123",
"role": "admin",
"exp": 1710000000
}
Signature Результат криптографической подписи:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
Подпись гарантирует целостность данных и подтверждает, что токен был создан сервером.
JWT не шифрует данные, а только подписывает. Payload читается любым, кто получил токен.
Зарезервированные claims:
iss — издатель токенаsub — идентификатор субъектаexp — время истеченияiat — время выпускаnbf — токен не действителен доПользовательские claims Используются для передачи ролей, прав, флагов доступа. В Fresh это удобно для серверных маршрутов и middleware.
В Deno отсутствует Node.js-специфичный jsonwebtoken, но
доступны совместимые библиотеки или стандартный Web Crypto API.
Пример с библиотекой djwt:
import { create, verify, getNumericDate } from "https://deno.land/x/djwt/mod.ts";
const key = "super-secret-key";
const payload = {
sub: "user_42",
role: "user",
exp: getNumericDate(60 * 60),
};
const token = await create(
{ alg: "HS256", typ: "JWT" },
payload,
key,
);
Токен формируется асинхронно и может быть возвращён клиенту в ответе API.
На практике используются два варианта:
HTTP-only cookie
Authorization header
Authorization: Bearer <token>
Для Fresh чаще выбирается cookie, так как серверный рендеринг может сразу учитывать данные пользователя.
Fresh поддерживает middleware через файл middleware.ts.
Проверка токена выполняется до обработки маршрута.
import { MiddlewareHandlerContext } from "$fresh/server.ts";
import { verify } from "https://deno.land/x/djwt/mod.ts";
const key = "super-secret-key";
export async function handler(
req: Request,
ctx: MiddlewareHandlerContext,
) {
const cookie = req.headers.get("cookie");
const token = cookie?.match(/auth=([^;]+)/)?.[1];
if (token) {
try {
const payload = await verify(token, key, "HS256");
ctx.state.user = payload;
} catch {
// недействительный токен
}
}
return await ctx.next();
}
ctx.state используется для передачи данных пользователя
в обработчики маршрутов и страницы.
В обработчике можно проверить наличие пользователя и его права:
export const handler = {
GET(_req: Request, ctx: HandlerContext) {
const user = ctx.state.user;
if (!user) {
return new Response("Unauthorized", { status: 401 });
}
if (user.role !== "admin") {
return new Response("Forbidden", { status: 403 });
}
return new Response("Admin content");
},
};
Это обеспечивает простой и прозрачный контроль доступа без дополнительной логики сессий.
JWT всегда должен иметь exp. Отсутствие срока делает
токен уязвимым.
Подход с refresh-токеном:
В Fresh refresh-эндпоинт реализуется как обычный API-маршрут.
Критические моменты:
Deno.envSameSite, Secure,
HttpOnly для cookieJWT — не замена полноценной системе безопасности, а транспорт данных с проверяемой подписью.
Fresh рендерит HTML на сервере, а интерактивность добавляется через islands. JWT используется только на серверной стороне:
Это исключает дублирование логики аутентификации в клиентском коде.
expJWT в Fresh работает эффективно при строгом соблюдении этих ограничений и использовании серверной модели обработки запросов.