Конфигурация входа и регистрации
Email + verification code, Google OAuth, signup allowlists и локальные test codes.
Multica поддерживает два способа входа: email + verification code (по умолчанию) и Google OAuth (optional). После успешного входа server выдаёт JWT cookie на 30 дней. На этой странице — настройка каждого способа, ограничение signup и главная ловушка self-hosted deployments.
Список env vars — Environment variables; токены и lifecycle — Authentication and tokens.
Как работает вход по email + verification code
Пользователь вводит email → server отправляет 6-digit code → пользователь вводит code → server проверяет → выдаётся JWT cookie. Стандартный поток. Два backend доставки — выберите под deployment:
Option A: Resend (рекомендуется для cloud / public internet)
-
Создайте аккаунт Resend и verify domain
-
Создайте API key
-
Задайте переменные окружения:
RESEND_API_KEY=re_xxxxxxxxxxxxxxxx RESEND_FROM_EMAIL=noreply@yourdomain.com # must be a domain verified in Resend -
Restart server
Option B: SMTP relay (self-hosted / on-premise)
Используйте, когда deployment не достигает api.resend.com или уже есть internal mail relay (Microsoft Exchange, Postfix, on-prem SendGrid и т. д.). SMTP_HOST имеет приоритет над RESEND_API_KEY, если оба заданы — при non-empty SMTP_HOST server всегда идёт через SMTP, даже если RESEND_API_KEY тоже configured, verification и invite mail не покидают internal network.
SMTP path поддерживает три режима relay, типичные для on-premise (в т. ч. Exchange receive connectors):
| Mode | Port | Auth | TLS |
|---|---|---|---|
| Anonymous internal relay | 25 | none — submission trusted by IP / subnet | none on the wire (internal segment only) |
| Authenticated submission | 587 | SMTP_USERNAME + SMTP_PASSWORD | STARTTLS, upgraded automatically |
| Implicit TLS (SMTPS) | 465 | optional (SMTP_USERNAME + SMTP_PASSWORD) | TLS handshake on connect — auto-enabled on port 465, or force on a non-standard port with SMTP_TLS=implicit |
Anonymous Exchange relay на port 25 — типичный internal SMTP relay / Exchange anonymous receive connector из trusted subnet без credentials:
SMTP_HOST=exchange.internal.example.com
SMTP_PORT=25
SMTP_USERNAME=
SMTP_PASSWORD=
SMTP_TLS_INSECURE=false
RESEND_FROM_EMAIL=noreply@yourdomain.com # reused as the From: headerAuthenticated submission на port 587 — relay требует service account; STARTTLS автоматически при advertise:
SMTP_HOST=smtp.internal.example.com
SMTP_PORT=587
SMTP_USERNAME=multica
SMTP_PASSWORD=...
SMTP_TLS_INSECURE=false # set true only for self-signed / private CA
RESEND_FROM_EMAIL=noreply@yourdomain.comImplicit TLS (SMTPS) на port 465 — провайдеры только с SMTPS без STARTTLS (Aliyun / Tencent enterprise mail). Port 465 auto-enables implicit TLS; SMTP_TLS=implicit (aliases: smtps, ssl) на non-standard SMTPS port:
SMTP_HOST=smtp.qiye.aliyun.com
SMTP_PORT=465 # implicit TLS auto-enabled on 465
SMTP_USERNAME=multica@yourdomain.com
SMTP_PASSWORD=...
SMTP_TLS=implicit # optional on 465; required on a non-standard SMTPS port
RESEND_FROM_EMAIL=noreply@yourdomain.comStrict public relays (Google Workspace smtp-relay.gmail.com) требуют valid EHLO name. Default localhost с public IP отклоняется — opaque EOF на later command (smtp auth: EOF). Задайте SMTP_EHLO_NAME — FQDN, который принимает relay; default — machine hostname, в container обычно не FQDN:
SMTP_HOST=smtp-relay.gmail.com
SMTP_PORT=587
SMTP_EHLO_NAME=mail.yourdomain.com # FQDN the relay accepts; defaults to the (non-FQDN) container hostname
RESEND_FROM_EMAIL=noreply@yourdomain.comПри старте server печатает выбранный provider и negotiated TLS — например EmailService: SMTP relay exchange.internal.example.com:25 (starttls) from=noreply@example.com или … smtp.qiye.aliyun.com:465 (implicit-tls) from=… (или Resend API / DEV mode). Password не логируется. Если после restart нет SMTP line — SMTP_HOST не дошёл до process (docker compose -f docker-compose.selfhost.yml exec backend env | grep SMTP).
Если не настроено ни одно: server не падает, но каждое письмо пишется только в stdout. Удобно локально; в production — чёрная дыра.
Fixed local testing codes
Не включайте fixed verification code на publicly reachable instance.
Старое поведение, когда non-production принимал 888888 по умолчанию, удалено. Без явной настройки 888888 — как любой неверный code.
Локальная разработка без email backend — generated code из server logs. Для deterministic local/private automation задайте MULTICA_DEV_VERIFICATION_CODE шестизначным значением вроде 888888 и держите APP_ENV non-production:
APP_ENV=development
MULTICA_DEV_VERIFICATION_CODE=888888Shortcut игнорируется при APP_ENV=production.
Production: пустой MULTICA_DEV_VERIFICATION_CODE и APP_ENV=production. При deploy через make selfhost / docker-compose.selfhost.yml APP_ENV default — production.
Google OAuth configuration
Optional. Без него — только email + verification code; с ним — «Sign in with Google» на странице входа.
-
OAuth 2.0 client в Google Cloud Console
-
Authorized redirect URIs — frontend Multica +
/auth/callback, например:https://multica.yourdomain.com/auth/callback -
Client ID и secret — три переменные:
GOOGLE_CLIENT_ID=xxxxx.apps.googleusercontent.com GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxxxxx GOOGLE_REDIRECT_URI=https://multica.yourdomain.com/auth/callback -
Restart server.
Runtime: frontend читает через /api/config — после смены restart server, без rebuild.
Redirect URI должен совпадать точно в Google Console и GOOGLE_REDIRECT_URI — protocol (http vs https), trailing slash, port. Любое расхождение — Google отклоняет OAuth; пользователь видит redirect_uri_mismatch.
Restricting who can sign up
Три env vars по приоритету:
Existing users всегда могут войти снова — signup allowlist только для first-time signup, не для returning users.
ALLOWED_EMAILS(highest priority) — explicit email allowlist, comma-separated. When non-empty, only listed emails can sign up.ALLOWED_EMAIL_DOMAINS— domain allowlist, comma-separated (for examplecompany.io,partner.com).ALLOW_SIGNUP— master switch, defaulttrue. Setfalseto disable signup entirely.
Три слоя — AND semantics, не OR. Частая ошибка: ALLOWED_EMAIL_DOMAINS=company.io + ALLOW_SIGNUP=true «company.io плюс все». Нет. Non-empty layer — emails вне списка отклоняются — ALLOW_SIGNUP=true не перебивает.
Чтобы «allow everyone» — все три empty (или только ALLOW_SIGNUP=true).
Typical configurations:
| Goal | Configuration |
|---|---|
Internal only, employees of company.io | ALLOWED_EMAIL_DOMAINS=company.io |
| Internal + a few external collaborators | ALLOWED_EMAIL_DOMAINS=company.io + collaborator addresses added to ALLOWED_EMAILS |
| Disable self-serve signup entirely, invite-only | ALLOW_SIGNUP=false |
| Open signup (not recommended for production) | All three empty |
Can you still invite people when signup is disabled?
Только у кого уже есть Multica account. Accept invite не проверяет signup allowlist — если invitee уже signed up (другой workspace), invite link + sign in → accept.
Never signed up — invite не спасёт. Перед accept нужен sign-in; первый шаг (verification code) проходит allowlist. При ALLOW_SIGNUP=false или email вне ALLOWED_EMAILS / ALLOWED_EMAIL_DOMAINS signup не завершится, invite не примет.
External collaborator без аккаунта: временно добавьте email в ALLOWED_EMAILS, дождитесь signup и accept, затем уберите entry.
Invites — Members and roles.
Далее
- Environment variables — определения всех variables этой страницы
- Authentication and tokens — JWT / PAT / daemon token
- Troubleshooting — code не пришёл, OAuth
redirect_uri_mismatch, signup rejected