# Self-hosting with team logins (`AUTH_MODE=team`) `team` mode turns the app into a single shared workspace with individual email/password logins. There is no billing, no Google login, no email verification, and no self-serve signup — the owner provisions every account. Use it when you want your team on one internal instance and need to see who did what. For a public multi-tenant product, use `hosted` instead. ## What you get - Email/password sign-in for each teammate. - One shared workspace (organization). Everyone works in the same projects. - Roles: **owner** (you), **admin** (full access except billing/owner actions), **member** (research + view). - Two ways to add people: - **Settings → Users** — create an account with a temporary password directly. - **Settings → Organization** — send an email invite link (needs no email provider config to create the invite; the link is shown in the UI). ## 1. Set environment variables Edit `.env` in the deployment directory (for the pm2 setup that is `/home/dev/DOCKER/OPEN-SEO/open-seo/.env`): ```sh AUTH_MODE=team BETTER_AUTH_URL=https://seo.thedomainnest.com # the exact public origin, https BETTER_AUTH_SECRET=<64 hex chars> # openssl rand -hex 32 ``` `AUTH_MODE` is compiled into the browser bundle, so it must be present when `vite build` runs — not only at runtime. Vite reads this same `.env` at build time, so one edit covers both as long as the build runs in this directory. Keep the existing `DATABASE_URL`, `DATAFORSEO_API_KEY`, etc. ## 2. Rebuild and restart If your pipeline builds on push, commit/push and let it run. To do it by hand: ```sh cd /home/dev/DOCKER/OPEN-SEO/open-seo pnpm install --frozen-lockfile pnpm build pm2 restart OPEN-SEO --update-env ``` Confirm config: `curl -s http://127.0.0.1:3001/api/health | jq .checks.auth` should report `team`. ## 3. Create the owner account Open the site. With `team` mode on and no users yet, `/sign-in` redirects to `/setup`. Fill in name, email, password → **Create workspace**. You are signed in as the owner. `/setup` disables itself the moment the owner exists. If you ever need to reset, delete all rows from `user` (and `member`, `account`, `session`) in Postgres and reload. ## 4. Add your team **Settings → Users → Add user.** Enter their email, name, a temporary password, and a role. Share the password out-of-band; they change it after signing in (Settings → Personal, once that lands) or you reset it from the same screen. Removing a user drops their membership and signs them out everywhere. Their `user` row is kept so past activity still attributes correctly; re-adding them issues a fresh password. ## Notes - Password reset by email is not available in `team` mode. The owner/admins reset passwords from Settings → Users. - The MCP server and its OAuth flow are hosted-only for now; `team` deployments serve the app UI only. - Rolling back: set `AUTH_MODE=local_noauth`, rebuild, restart. Existing users and data stay in the database, just unused.