Создание продукта14 мин

Как сделать регистрацию и личный кабинет через Supabase Auth

Пошаговый гайд по регистрации, подтверждению email, сессиям, профилю и защите данных в личном кабинете через Supabase Auth.

Обложка статьи: Как сделать регистрацию и личный кабинет через Supabase AuthЧеловек 2.0
≡
Коротко

Что забрать из статьи

  • 1Регистрация считается готовой после подтверждения email, входа, восстановления сессии и повторного чтения профиля.
  • 2Publishable key допустим во frontend; secret key остаётся только на доверенном backend и обходит RLS.
  • 3Grants, RLS и тест двумя пользователями должны блокировать чтение, изменение и удаление чужого профиля.
Где это применять

Что должно работать в готовом сценарии

Форма регистрации сама по себе ещё не создаёт личный кабинет. Рабочий сценарий начинается с новой учётной записи и заканчивается только тогда, когда человек подтвердил email, вошёл, увидел свои данные, обновил профиль, перезагрузил страницу и не получил доступ к чужой записи.

В этом гайде мы соберём именно такой путь: Supabase Auth отвечает за личность и сессию, таблица public.profiles хранит данные кабинета, а права Postgres и Row Level Security ограничивают операции владельцем строки. Пример ориентирован на JavaScript и supabase-js v2; для Next.js с серверным рендерингом отдельно разберём cookie-сессию.

Что понадобится до начала

Нужны проект Supabase, приложение на JavaScript или TypeScript и пакет @supabase/supabase-js. В клиентском приложении используйте Project URL и актуальный publishable key. Такой ключ можно включать в браузерный код, но он не защищает данные сам по себе: до входа запросы идут с ролью anon, после входа права определяют пользовательский JWT, grants и RLS.

Secret key предназначен только для доверенного backend и обходит RLS. Никогда не помещайте его во frontend, мобильное приложение, публичный репозиторий, URL или клиентские логи. Старые anon и service_role ещё встречаются в проектах, но Supabase относит их к legacy JWT-ключам и рекомендует переходить на publishable и secret keys.

Шаг 1. Создайте безопасный клиент Supabase

Установите клиентскую библиотеку командой npm install @supabase/supabase-js. Затем создайте один браузерный клиент с Project URL и publishable key, переданными через публичные переменные сборки. В статье намеренно нет реальных значений, доменов проекта и ключей.

Проверка шага: приложение собирается, клиент создаётся без ошибки, а в исходниках и логах отсутствует secret key. Не пытайтесь скрыть publishable key как пароль; безопасность пользовательских строк обеспечивается правами базы и RLS.

Шаг 2. Зарегистрируйте пользователя и обработайте подтверждение email

Для регистрации вызовите supabase.auth.signUp({ email, password }). Всегда обрабатывайте оба результата: data и error. Не журналируйте пароль, access token, refresh token или полную сессию.

В hosted-проектах подтверждение email обычно включено. В этом случае signUp возвращает объект пользователя, а session остаётся null. Интерфейс должен показать состояние «Проверьте почту», а не сразу отправлять человека в кабинет. При отключённом подтверждении пользователь и сессия обычно доступны сразу.

Если передаёте emailRedirectTo, адрес должен входить в Redirect URLs allowlist. Site URL используется как маршрут по умолчанию для подтверждения и восстановления. Для production лучше перечислить точные URL, а широкие wildcard оставить локальной разработке и preview-средам.

Путь регистрации: данные формы, подтверждение email, сессия и открытый личный кабинет

Шаг 3. Сделайте вход и выход

Вход по email и паролю выполняется через supabase.auth.signInWithPassword({ email, password }). Успех означает, что клиент получил сессию и может делать запросы от роли authenticated. Ошибку показывайте нейтрально: не раскрывайте, существует ли конкретный email, и не пересылайте человеку технический ответ целиком.

Обычный supabase.auth.signOut() использует глобальный scope и завершает активные сессии пользователя. Для выхода только из текущего браузера передайте { scope: "local" }. Refresh tokens отзываются, однако уже выданный access token может действовать до времени exp. Для критичных действий учитывайте это окно отдельно.

Шаг 4. Разделите учётную запись и данные профиля

Схема auth хранит служебные данные Supabase Auth и не открыта через автоматически созданный Data API. Для имени, аватара, настроек и других полей кабинета создайте public.profiles. Идентификатор профиля должен ссылаться на первичный ключ auth.users.id; обычно применяют on delete cascade.

Роль и полномочия нельзя доверять изменяемому user_metadata. Эти данные человек может обновлять. Используйте их для презентационных полей, а права храните в контролируемом приложением источнике.

Запись профиля можно создавать после регистрации из приложения или триггером. Ошибка триггера способна заблокировать signup, поэтому такой путь требует отдельного теста и функции security definer с явно заданным search_path.

Шаг 5. Ограничьте доступ grants и RLS

Включите Row Level Security для public.profiles, выдайте ролям только необходимые права и создайте отдельные политики для операций. Для SELECT и DELETE применяется using. Для INSERT нужен with check. Для UPDATE нужны using и with check, а также подходящая SELECT policy.

Правило владельца сопоставляет текущего authenticated-пользователя с user_id или id строки, например (select auth.uid()) = user_id. Добавьте индекс на поле владельца. Фильтр в интерфейсе не является защитой: запрос можно отправить напрямую.

Проверка должна включать анонимного посетителя, владельца A и постороннего пользователя B. Убедитесь, что B не читает, не создаёт строку с чужим user_id, не меняет владельца и не удаляет запись A. Запрещённая операция иногда возвращает ноль строк без исключения, поэтому проверяйте и состояние базы.

RLS разделяет записи двух пользователей и разрешает доступ только владельцу

Шаг 6. Загрузите профиль в личном кабинете

После входа получите подтверждённого пользователя через supabase.auth.getUser(), затем запросите профиль по его id. На клиенте состояние кабинета должно различать загрузку, успешный ответ, отсутствие профиля, истёкшую сессию и сетевую ошибку.

При обновлении профиля отправляйте только разрешённые поля. user_id должен определяться из подтверждённой сессии и проходить with check в RLS. После сохранения перечитайте запись из базы и покажите фактически сохранённые данные.

Шаг 7. Правильно восстановите сессию

В чистом браузерном приложении supabase-js сохраняет и обновляет сессию. После перезагрузки дождитесь инициализации Auth, затем загрузите пользователя и профиль. Не показывайте защищённое содержимое до завершения проверки.

В Next.js с SSR используйте @supabase/ssr, отдельный server client на запрос и cookies. Актуальная документация Supabase для Next.js использует Proxy для обновления токенов и записи новых cookies. На сервере не считайте результат getSession доказательством личности: для защищённых страниц и данных используйте проверку, которая обращается к Auth-серверу, например getUser, а в текущем SSR-руководстве — getClaims.

Шаг 8. Добавьте восстановление пароля

Восстановление состоит из двух этапов. Сначала вызовите resetPasswordForEmail с разрешённым redirectTo. После перехода по письму на защищённой странице задайте новый пароль через updateUser({ password }).

Для SSR и PKCE может понадобиться серверный endpoint, который обменивает token_hash через verifyOtp. Маршрут возврата должен быть в allowlist. Не передавайте токен письма в аналитические события, сторонние логи или публичные ссылки.

Как проверить результат двумя пользователями

Создайте два тестовых аккаунта в изолированной среде. Пользователь A регистрируется, подтверждает email, входит, создаёт профиль, меняет имя и после перезагрузки видит сохранённый результат. Пользователь B проходит тот же путь со своей записью.

Теперь отправьте запросы B к записи A: чтение, изменение, попытку подменить владельца и удаление. Все они должны не изменить чужую строку. Затем выйдите из аккаунта и повторите чтение как anon. Зафиксируйте ожидаемый статус интерфейса и фактическое состояние базы.

Критерий готовности: новый человек проходит регистрацию без помощи разработчика, понимает письмо подтверждения, возвращается в приложение, видит свой кабинет, сохраняет данные, повторно входит после закрытия браузера и не может получить чужой профиль.

Типичные ошибки и точная диагностика

После signUp нет перехода в кабинет. Проверьте, включено ли подтверждение email. При session = null это ожидаемое состояние; покажите экран с инструкцией и возможностью повторить письмо.

Ссылка из письма ведёт не туда. Сверьте Site URL, redirectTo и Redirect URLs allowlist. Проверьте точное различие production, preview и локального адреса.

После обновления страницы человек разлогинен. Для браузерного приложения проверьте создание клиента и инициализацию Auth. Для SSR проверьте request-specific client, чтение и запись cookies, Proxy и отсутствие кеширования ответа между пользователями.

Профиль не создаётся. Проверьте внешний ключ, grants, INSERT policy и with check. Если используется триггер, посмотрите его ошибку: сбой триггера может остановить саму регистрацию.

Пользователь видит чужие строки. Остановите выпуск. Проверьте, включён ли RLS, какие grants выданы anon и authenticated, все CRUD-политики и прямой запрос под вторым аккаунтом.

В браузер попал secret key. Уберите источник утечки, создайте новый secret key, замените его во всех доверенных компонентах, проверьте переход и удалите старый. Не публикуйте значение в баг-трекере или переписке.

Ограничения, которые важно учитывать

Supabase Auth берёт на себя хранение учётных записей, выпуск сессий и основные auth-маршруты. Он не проектирует за вас модель профиля, роли, бизнес-права, тексты ошибок, резервное восстановление и пользовательский опыт.

Защита от перебора, CAPTCHA, rate limits, MFA и дополнительные проверки зависят от риска продукта. Для платежей, медицинских данных и других чувствительных сценариев нужен отдельный разбор угроз и тестирование безопасности.

Повторный signUp на существующий email может давать нейтральный ответ в зависимости от настроек подтверждения и защиты от перечисления пользователей. Не стройте интерфейс на обещании точной ошибки «email уже зарегистрирован».

Частые вопросы

Можно ли хранить имя прямо в user_metadata? Да, для презентационных полей. Для ролей и полномочий этот источник не подходит, потому что пользователь может менять свои метаданные.

Можно ли показывать publishable key во frontend? Да. Это публичный идентификатор клиента. Данные защищают точные grants и RLS. Secret key во frontend запрещён.

Почему после signOut запрос ещё может пройти? Уже выпущенный JWT остаётся действительным до exp. Sign out отзывает refresh tokens и удаляет локальную сессию, но не отзывает прошлое время у access token.

Что делать дальше

Начните с одного законченного пути: signup → подтверждение email → вход → профиль → обновление → повторный вход → проверка вторым пользователем. Только после этого добавляйте OAuth, MFA, роли и соседние разделы кабинета.

Если интерфейс уже готов, сначала проверьте весь путь от экрана до сохранённых данных в статье «Есть красивый frontend — что делать дальше, чтобы получился работающий продукт».

На воркшопе «Человек 2.0» Codex + Hermes участники собирают базу, пользователей, личный кабинет, заявки, профили, заказы, админку и CRM на своём проекте. Посмотреть программу можно на официальной странице воркшопа.

Источники

Дальше читать

Связанные материалы

Все статьи →
Практика11 мин

Как проверить пользовательские сценарии сайта перед запуском

Практический prelaunch-чек: как выбрать критические пути сайта, пройти успех и ошибки, проверить формы, мобильный сценарий и зафиксировать доказательства до релиза.

Открыть статью→
Создание продукта12 мин

Есть красивый frontend — что делать дальше, чтобы получился работающий продукт

Практический план перехода от красивого frontend-демо к работающему продукту: главный пользовательский путь, данные, авторизация, backend, storage, права доступа, логи, тесты и критерии готовности.

Открыть статью→
Дизайн с ИИ13 мин

Как проверить мобильную версию сайта, сделанного ИИ

Пошаговая проверка адаптивности сайта: ширины экрана, формы, модальные окна, клавиатурный фокус, доступность, реальный телефон и один полезный тест Playwright.

Открыть статью→