Skip to content

Auth & audiences setup

The portal supports two authentication modes: supabase (OAuth and email/password, with in-app audience management) and password (bcrypt-hashed secrets in environment variables, a developer fallback). Use supabase for all real deployments.

Set AUTH_PROVIDER in your .env (or in the Netlify environment variables):

AUTH_PROVIDER=supabase

Omit AUTH_PROVIDER or set it to password to use password-only auth. In password mode, audiences are defined entirely by the VIEWER_<NAME>_PASSWORD environment variables — they cannot be managed in the editor UI.

All client sites share one Supabase project. Every *.drawn.guide site does OAuth, invite, and password-reset flows against the same Auth instance. The three required env vars are the same across all client sites:

SUPABASE_URL=https://your-project.supabase.co
SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key

Each site has a default viewer audience seeded at site creation. The isDefault flag is a Supabase-only concept — it marks the audience that viewers fall into when they authenticate without being assigned to a named audience. This is set in the database at provisioning time and does not appear in password-mode sites.

The following rules apply to the Supabase dashboard (the production source of truth). Do not apply them via supabase config push — the monorepo’s supabase/config.toml has site_url set to localhost and would clobber production settings.

Site URL — set to a single concrete origin:

https://acme.drawn.guide

Wildcards are rejected in the Site URL field and a wildcard entry silently breaks the fallback path for every site. Pick one concrete domain as the Site URL (typically the main client site or the first site created).

Redirect URL allow-list — restrict to platform-controlled paths:

https://*.drawn.guide/edit/login
https://*.drawn.guide/edit/login/callback

These are the only two paths any auth flow redirects to: OAuth and invite/reset flows use /edit/login/callback; the existing-user invite login link uses /edit/login. Path-restricting the allow-list means a wildcard subdomain entry cannot be abused to redirect to an arbitrary page on any drawn.guide subdomain.

Never add a bare *.netlify.app entry. netlify.app is a shared hosting domain — any Netlify tenant could register a subdomain and become a valid redirect target in your allow-list, enabling an open-redirect attack that could steal auth codes.

The portal builds the OAuth redirect_to parameter from the live request origin, not from the build-time SITE environment variable. This is required because Netlify’s URL environment variable (which Astro bakes into import.meta.env.SITE) can resolve to the *.netlify.app host instead of the custom domain — making redirect_to unmatched in the allow-list and landing the PKCE callback on a different origin from where the verifier cookie was set.

Any custom auth flow you add must derive its redirect origin from the incoming request, not from import.meta.env.SITE.

In password mode, audiences are defined by environment variables. Each audience needs a name (the <NAME> suffix), a bcrypt password hash, and optionally a display color:

VIEWER_INTERNAL_PASSWORD=\$2b\$10\$...
VIEWER_INTERNAL_COLOR=#10b981
VIEWER_EXTERNAL_PASSWORD=\$2b\$10\$...
VIEWER_EXTERNAL_COLOR=#3b82f6

See Environment variables for the bcrypt hash generation command and the \$-escaping requirement.

Audience settings are read-only in the editor UI when running in password mode. To add or remove an audience, edit the environment variables and redeploy.