Token-based аутентификация основана на передаче клиенту специального маркера (токена), который подтверждает его подлинность при последующих запросах. В отличие от сессионной аутентификации, где состояние хранится на сервере, токены позволяют реализовать stateless-архитектуру, что особенно важно для распределённых систем, edge-приложений и serverless-подхода, на котором построен Fresh.
Ключевые свойства модели:
В экосистеме JavaScript токены чаще всего представлены в виде JWT (JSON Web Token), хотя сама модель не ограничивается только этим форматом.
Fresh — фреймворк для Deno с акцентом на:
Это накладывает важные ограничения и преимущества при проектировании аутентификации:
По этой причине cookie-based token storage является предпочтительным вариантом по сравнению с localStorage.
JWT состоит из трёх частей, закодированных в Base64URL и разделённых точками:
header.payload.signature
Header Содержит информацию о типе токена и алгоритме подписи:
{
"alg": "HS256",
"typ": "JWT"
}
Payload Набор утверждений (claims):
sub — идентификатор пользователяexp — время истеченияiat — время выпускаiss — издательSignature Результат подписи header + payload с использованием секретного ключа или приватного ключа.
В Fresh токены обычно подписываются на сервере с использованием
стандартного crypto.subtle.
Set-CookieПример установки cookie:
ctx.response.headers.set("Set-Cookie",
"access_token=...; HttpOnly; Secure; SameSite=Strict; Path=/"
);
Критически важные флаги:
Каждый последующий запрос автоматически содержит cookie. Fresh-middleware перехватывает его до выполнения обработчика маршрута.
export async function handler(req: Request, ctx: FreshContext) {
const token = getCookies(req.headers).access_token;
}
После извлечения токена:
ctx.stateMiddleware — ключевая точка реализации token-based аутентификации.
Пример глобального middleware:
export async function handler(req, ctx) {
const cookies = getCookies(req.headers);
const token = cookies.access_token;
if (token) {
const payload = await verifyJWT(token);
ctx.state.user = payload;
}
return await ctx.next();
}
Преимущества такого подхода:
На уровне маршрута проверяется наличие
ctx.state.user.
if (!ctx.state.user) {
return new Response("Unauthorized", { status: 401 });
}
Для сложных сценариев:
Для повышения безопасности применяется двухтокенная схема.
Access Token
Refresh Token
Схема обновления:
/auth/refreshВ Fresh refresh-маршрут реализуется как обычный серверный endpoint без клиентского JS.
Поскольку JWT stateless, отзыв токена требует дополнительных механизмов:
В Deno-окружении часто используется:
Пример проверки версии:
if (payload.version !== user.tokenVersion) {
throw new Error("Token revoked");
}
При использовании cookie-based токенов CSRF остаётся актуальной угрозой.
Методы защиты:
Для Fresh оптимален double submit:
Fresh выполняет серверный рендеринг при каждом запросе. Это позволяет:
Пример:
if (!ctx.state.user) {
return ctx.render({ user: null });
}
HTML никогда не содержит токен, а только данные, полученные после его проверки.
Распространённые проблемы:
expВ контексте Fresh особенно критично избегать утечек через серверные логи и edge-окружения.
Корректная token-based аутентификация в Fresh строится на следующих принципах:
Такой подход полностью соответствует философии Fresh и позволяет строить безопасные, масштабируемые JavaScript-приложения без избыточной сложности.