Авторизация и сессии
Сессии в БД или JWT, где хранить токен, DAL и библиотеки авторизации.
Обновлено
Что такое аутентификация, авторизация и сессия
Три разных понятия, которые часто путают:
| Понятие | Вопрос | Пример |
|---|---|---|
| Аутентификация | Кто вы? | вход по email + паролю, через Google, magic link |
| Сессия | Как узнать вас при следующем запросе? | cookie, автоматически отправляемый с каждым запросом |
| Авторизация | Вам это можно? | удалить пост может только его автор |
Как они работают вместе: вы входите один раз → сервер создаёт сессию и ставит cookie → при каждом запросе сервер читает cookie, понимает, кто вы, и проверяет, что вам можно (авторизация).
Два вида сессий
Сессия в базе данных (stateful)
В cookie лежит только случайный id. Данные сессии (пользователь, срок) хранятся на сервере, в таблице sessions или в Redis.
Сессия в cookie (stateless, JWT)
В cookie лежат сами данные (userId, срок), подписанные (или зашифрованные) секретным ключом сервера. Сервер проверяет подпись — без запроса к базе. Распространённый формат — JWT.
| Сессия в БД | Stateless (JWT в cookie) | |
|---|---|---|
| Что в cookie | случайный id | данные с подписью |
| Запрос к БД на каждый запрос | да (или кэш) | нет |
| Мгновенный выход / отзыв | да — удалить строку | сложно — токен действует до истечения |
| «Выйти на всех устройствах» | легко | сложно |
| Размер cookie | маленький | больше |
| Когда | приложения с чувствительными данными, тонкий контроль | простые приложения, много серверов без общей БД |
Где хранить токен — важное правило
| Место | Вердикт |
|---|---|
cookie HttpOnly; Secure; SameSite=Lax |
✓ правильно — JS не может его прочитать, значит, и внедрённый скрипт тоже (XSS) |
localStorage / sessionStorage |
✗ любой скрипт на странице может его украсть |
| переменная в памяти (SPA) | возможно, но теряется при перезагрузке; нужен refresh token в cookie |
Access token и refresh token
Для API часто используют два токена:
| Access token | Refresh token | |
|---|---|---|
| Срок | короткий (минуты) | долгий (дни, недели) |
| Используется | в каждом запросе | только чтобы получить новый access token |
| Если украден | ущерб ограничен по времени | можно отозвать на сервере |
Сессии в Next.js — составные части
// shared/api/session.ts
import 'server-only'
import { SignJWT, jwtVerify } from 'jose'
import { cookies } from 'next/headers'
const key = new TextEncoder().encode(process.env.SESSION_SECRET)
export async function createSession(userId: string) {
const expires = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
const token = await new SignJWT({ userId }).setProtectedHeader({ alg: 'HS256' }).setExpirationTime(expires).sign(key)
;(await cookies()).set('session', token, { httpOnly: true, secure: true, sameSite: 'lax', expires, path: '/' })
}
export async function readSession() {
const token = (await cookies()).get('session')?.value
if (!token) return null
try {
return (await jwtVerify(token, key, { algorithms: ['HS256'] })).payload as { userId: string }
} catch {
return null
}
}Где проверять — слои
| Слой | Роль | Достаточно ли одного? |
|---|---|---|
proxy.ts |
оптимистичная проверка: «есть cookie?» → редирект на /login |
нет — только UX, быстро |
Data Access Layer (verifySession) |
по-настоящему проверяет сессию, один раз на запрос (cache()) |
да — здесь безопасность |
| каждый Server Action / Route Handler | аутентификация + авторизация на конкретный ресурс | обязательно |
| интерфейс (скрыть кнопки) | только удобство | никогда |
// shared/api/dal.ts
import 'server-only'
import { cache } from 'react'
import { redirect } from 'next/navigation'
export const verifySession = cache(async () => {
const session = await readSession()
if (!session) redirect('/login')
return session
})Layout не перепроверяют сессию при каждой навигации (они сохраняются). Ставьте проверку в страницу, в DAL или в действие — не только в layout.
Библиотеки — не пишите аутентификацию сами
| Библиотека | Тип | Когда |
|---|---|---|
| Auth.js (NextAuth) | open source, внутри приложения | OAuth (Google, GitHub), сессии в БД или JWT |
| Better Auth | open source, внутри приложения | email/пароль, OAuth, 2FA, организации — полно и типизировано |
| Clerk, Auth0, WorkOS, Stack Auth | облачный сервис | готовый UI, enterprise (SSO), без поддержки |
| iron-session, jose | только сессии | логика входа уже есть, нужен только cookie |
В аутентификации много нюансов безопасности (хеширование паролей, rate limiting, сброс пароля, CSRF). Зрелая библиотека почти всегда правильный выбор.
Коротко
- Аутентификация = кто вы; сессия = как вас узнать; авторизация = что вам можно.
- Сессия в БД = лёгкий отзыв; JWT в cookie = без запроса к БД, отзыв сложный.
- Токен — в cookie
HttpOnly; проверяете в DAL и в каждом действии, proxy — только оптимистичная проверка.