mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-05 21:39:54 +02:00
* fix: gate dev verification code behind explicit env * docs: fold dev verification code into env table * docs: clarify fixed verification code opt-in --------- Co-authored-by: Eve <eve@multica.ai>
129 lines
6.7 KiB
Plaintext
129 lines
6.7 KiB
Plaintext
---
|
|
title: Sign-in and signup configuration
|
|
description: Configure email + verification code sign-in, Google OAuth, signup allowlists, and local test codes.
|
|
---
|
|
|
|
import { Callout } from "fumadocs-ui/components/callout";
|
|
import { Mermaid } from "@/components/mermaid";
|
|
|
|
Multica supports two sign-in methods: **email + verification code** (default) and **Google OAuth** (optional). On successful sign-in, the server issues a JWT cookie with a 30-day lifetime. This page covers how to configure each method, how to restrict who can sign up, and the single biggest trap for self-hosted deployments.
|
|
|
|
For the list of environment variables referenced below, see [Environment variables](/environment-variables); for token usage and lifecycle details, see [Authentication and tokens](/auth-tokens).
|
|
|
|
## How email + verification code sign-in works
|
|
|
|
The user enters an email on the sign-in page → the server sends a 6-digit code → the user enters it → the server verifies it → a JWT cookie is issued. Standard flow. It requires [Resend](https://resend.com/) as the email provider:
|
|
|
|
1. Create a Resend account and verify your domain
|
|
2. Create an API key
|
|
3. Set the environment variables:
|
|
|
|
```bash
|
|
RESEND_API_KEY=re_xxxxxxxxxxxxxxxx
|
|
RESEND_FROM_EMAIL=noreply@yourdomain.com # must be a domain verified in Resend
|
|
```
|
|
|
|
4. Restart the server
|
|
|
|
**What happens if you don't set `RESEND_API_KEY`**: the server doesn't error, but **every email that should have been sent is written to the server's stdout only**. Handy for local development (copy the code from the logs); in production it's a black hole.
|
|
|
|
## Fixed local testing codes
|
|
|
|
<Callout type="warning">
|
|
**Do not enable a fixed verification code on a publicly reachable instance.**
|
|
|
|
The old behavior where non-production instances accepted `888888` by default has been removed. Unless you explicitly configure it, typing `888888` is treated like any other wrong code.
|
|
|
|
Local development without Resend should use the generated code printed in server logs. If you need deterministic local/private automation, set `MULTICA_DEV_VERIFICATION_CODE` to a 6-digit value such as `888888`, and keep `APP_ENV` non-production:
|
|
|
|
```bash
|
|
APP_ENV=development
|
|
MULTICA_DEV_VERIFICATION_CODE=888888
|
|
```
|
|
|
|
This shortcut is ignored when `APP_ENV=production`.
|
|
</Callout>
|
|
|
|
Production deployments should leave `MULTICA_DEV_VERIFICATION_CODE` empty and set `APP_ENV=production`. If you deploy via `make selfhost` / `docker-compose.selfhost.yml`, `APP_ENV` defaults to `production`.
|
|
|
|
## Google OAuth configuration
|
|
|
|
Optional. Without it, only email + verification code is available; with it, the sign-in page gets a "Sign in with Google" button.
|
|
|
|
1. Create an OAuth 2.0 client in the [Google Cloud Console](https://console.cloud.google.com/)
|
|
2. Set the **Authorized redirect URIs** to your Multica frontend address plus `/auth/callback`, for example:
|
|
|
|
```text
|
|
https://multica.yourdomain.com/auth/callback
|
|
```
|
|
|
|
3. Once you have the client ID and client secret, set three environment variables:
|
|
|
|
```bash
|
|
GOOGLE_CLIENT_ID=xxxxx.apps.googleusercontent.com
|
|
GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxxxxx
|
|
GOOGLE_REDIRECT_URI=https://multica.yourdomain.com/auth/callback
|
|
```
|
|
|
|
4. Restart the server.
|
|
|
|
**Takes effect at runtime**: the frontend reads these settings at runtime via `/api/config` — after changing them, restart the server and the frontend picks up the new values with no rebuild or redeploy.
|
|
|
|
<Callout type="warning">
|
|
**The redirect URI must match exactly in both the Google Console and `GOOGLE_REDIRECT_URI`** — including protocol (`http` vs `https`), trailing slash, and port. Any mismatch and Google rejects the entire OAuth flow; the error shown to the user is `redirect_uri_mismatch`.
|
|
</Callout>
|
|
|
|
## Restricting who can sign up
|
|
|
|
Three environment variables combine by priority:
|
|
|
|
<Mermaid chart={`
|
|
graph TD
|
|
Start[New user first sign-in] --> A{Email in<br/>ALLOWED_EMAILS?}
|
|
A -- Yes --> Allow[Allow signup]
|
|
A -- No --> B{Domain in<br/>ALLOWED_EMAIL_DOMAINS?}
|
|
B -- Yes --> Allow
|
|
B -- No --> C{Any allowlist<br/>non-empty?}
|
|
C -- Yes --> Block[Reject]
|
|
C -- No --> D{ALLOW_SIGNUP<br/>= true?}
|
|
D -- Yes --> Allow
|
|
D -- No --> Block
|
|
`} />
|
|
|
|
**Existing users can always sign in again** — the signup allowlist only applies to **first-time signup**, not 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 example `company.io,partner.com`).
|
|
- **`ALLOW_SIGNUP`** — master switch, default `true`. Set `false` to disable signup entirely.
|
|
|
|
<Callout type="warning">
|
|
**The three layers are AND semantics, not OR.** A common wrong intuition is that `ALLOWED_EMAIL_DOMAINS=company.io` + `ALLOW_SIGNUP=true` means "allow company.io plus everyone else." It does **not**. If any layer has a non-empty value, **emails not matching it are rejected outright** — `ALLOW_SIGNUP=true` does not override that.
|
|
|
|
To actually "allow everyone," leave all three variables empty (or keep `ALLOW_SIGNUP=true`).
|
|
</Callout>
|
|
|
|
**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?
|
|
|
|
**Only people who already have a Multica account.** Accepting an invite doesn't check the signup allowlist — if the invitee has signed up already (for example in another workspace), clicking the invite link and signing in lets them accept.
|
|
|
|
**But people who have never signed up cannot be rescued by an invite.** Before accepting, they must sign in, and the first step of sign-in (requesting the verification code) passes through the signup allowlist check. If `ALLOW_SIGNUP=false`, or their email isn't in `ALLOWED_EMAILS` / `ALLOWED_EMAIL_DOMAINS`, they **cannot complete signup**, and therefore cannot accept the invite.
|
|
|
|
To invite an external collaborator who hasn't signed up yet: temporarily add their email to `ALLOWED_EMAILS`, wait for them to sign up and accept the invite, then remove the entry.
|
|
|
|
For how to create and use invites, see [Members and roles](/members-roles).
|
|
|
|
## Next
|
|
|
|
- [Environment variables](/environment-variables) — full definitions of every variable used on this page
|
|
- [Authentication and tokens](/auth-tokens) — JWT / PAT / daemon token categories and usage
|
|
- [Troubleshooting](/troubleshooting) — verification code not received, OAuth `redirect_uri_mismatch`, signup rejected
|