К блогу

Аутентификация и сессии

Аутентификация — фундамент любого SaaS. В шаблоне она построена на better-auth: современная библиотека с поддержкой email/password, сессий в БД, CSRF-защиты и расширяемых плагинов. Вам не нужно писать хеширование паролей и rotation сессий с нуля.

Конфигурация сосредоточена в app/lib/auth/auth.server.ts. Там задаётся адаптер Drizzle для PostgreSQL, секрет из BETTER_AUTH_SECRET, базовый URL из APP_URL и настройки cookies. Любая смена домена в production начинается с проверки APP_URL.

Пользовательский интерфейс auth разбит на маршруты: /auth/login, /auth/signup, /auth/forgot-password, /auth/reset-password. Общий layout auth.tsx обеспечивает единый стиль форм. Каждая форма — controlled inputs Mantine с обработкой ошибок от action.

Валидация входных данных — через Zod-схемы в app/lib/validation/auth.schemas.ts. Пароль: минимальная длина, требования к сложности (если включены). Email: нормализация и проверка формата. Ошибки валидации возвращаются в action и отображаются под полями — без generic «что-то пошло не так».

Парсинг form data вынесен в parse-form.server.ts с тестами. Это мелочь, но она предотвращает класс багов: неожиданные поля, пустые строки вместо undefined, дублирование логики между signup и login.

После успешной регистрации better-auth создаёт пользователя и сессию, браузер получает HttpOnly session cookie. Loader в _app.tsx на каждом защищённом маршруте вызывает getSession: если сессии нет — redirect на /auth/login с returnUrl.

Сброс пароля работает через email. Пользователь вводит email на forgot-password, сервер генерирует одноразовый token, отправляет ссылку через SMTP. На reset-password token проверяется, новый пароль хешируется, старые сессии инвалидируются.

Для production обязательно настройте SMTP в .env: host, port, user, password, from-адрес. Без SMTP сброс пароля молча не сработает — проверьте логи email.server.ts при отладке. APP_URL должен указывать на публичный HTTPS-домен, иначе ссылки в письмах ведут на localhost.

Админские маршруты под /admin имеют второй уровень защиты. Помимо сессии loader сверяет email пользователя со списком ADMIN_EMAILS в app/lib/config/admin.ts. Обычный залогиненный пользователь увидит 403, а не админку.

Интеграция с аналитикой: при signup и login вызываются trackServerEvent с типами signup_completed и login_completed. Одновременно stitch связывает visitorId с новым userId — воронка в админке остаётся непрерывной.

API-маршрут api/auth/$ ловит все better-auth endpoints (sign-in, sign-out, session и т.д.). Не создавайте дублирующие handlers — расширяйте конфиг better-auth плагинами, если нужны OAuth или magic links.

Тесты auth.schemas.test.ts и integration-тесты с seed-данными покрывают happy path и граничные случаи. При изменении требований к паролю обновите и схему, и тесты, и текст подсказки на форме signup.