VR3 AI ships with a built-in local authentication provider (email + password, backed by a signed JWT). This is the default and needs no external service. There is no public signup — an administrator creates user accounts in the Admin panel, and each user is prompted to change their password on first login. To offer social logins (Google, GitHub, and others), you can delegate sign-in to Stack Auth. Enabling it is a runtime configuration change — set a few environment variables and restart. The prebuilt dograhai/dograh-api and dograhai/dograh-ui images work as-is; you do not need to rebuild or build from source.
The active provider is controlled by the backend AUTH_PROVIDER variable (local by default). The frontend discovers the provider — and, for Stack, its public client config — at runtime from the backend’s /api/v1/health response, so the browser bundle never needs Stack values baked in at build time.

How it works

  1. The backend reads AUTH_PROVIDER and the Stack settings from its environment.
  2. When AUTH_PROVIDER=stack, /api/v1/health returns the public Stack client config (project id + publishable client key).
  3. The UI fetches that at runtime and initializes the Stack SDK in the browser.
  4. The secret server key is used only server-side (by the backend and the UI’s server runtime) and is never sent to the browser.

Prerequisites

A Stack Auth project. Create one in the Stack Auth dashboard and configure the social login providers you want to offer.

Step 1 — Collect your Stack credentials

From your project in the Stack Auth dashboard, gather:
ValueSensitivity
Project IDPublic
Publishable client keyPublic (safe to expose in the browser)
Secret server keySecret — keep server-side only
API base URLPublic. For Stack’s hosted service this is https://api.stack-auth.com

Step 2 — Configure the backend (api)

Set these on the api service. Add them to the environment: block of the api service in your docker-compose.yaml:
docker-compose.yaml
services:
  api:
    environment:
      AUTH_PROVIDER: "stack"
      STACK_AUTH_PROJECT_ID: "<your-project-id>"
      STACK_PUBLISHABLE_CLIENT_KEY: "<your-publishable-client-key>"
      STACK_SECRET_SERVER_KEY: "<your-secret-server-key>"
      STACK_AUTH_API_URL: "https://api.stack-auth.com"

Step 3 — Configure the UI (ui)

The UI runs server-side code (SSR pages and the /handler/* auth routes) that calls Stack with the secret server key, so the ui service needs that one value too:
docker-compose.yaml
services:
  ui:
    environment:
      STACK_SECRET_SERVER_KEY: "<your-secret-server-key>"
The ui service does not need the project id or publishable client key — it receives those from the backend at runtime via /api/v1/health. Only the secret server key (used server-side) is set here.

Step 4 — Restart and verify

Recreate the containers so they pick up the new environment:
docker compose up -d
Confirm the backend reports the active provider and the public client config:
curl -s http://localhost:8000/api/v1/health
# expect: "auth_provider":"stack", plus "stack_project_id" and "stack_publishable_client_key"
Then open the UI. The sign-in page should now present your configured Stack Auth social login options instead of the local email/password form.

Environment variable reference

VariableServiceSecretNotes
AUTH_PROVIDERapiSet to stack (default local)
STACK_AUTH_PROJECT_IDapiNoStack project ID; served to the UI at runtime
STACK_PUBLISHABLE_CLIENT_KEYapiNoPublishable key; served to the UI at runtime
STACK_SECRET_SERVER_KEYapi + uiYesServer-side only — never exposed to the browser
STACK_AUTH_API_URLapiNoStack REST API base URL
STACK_SECRET_SERVER_KEY is the only secret here. Keep it out of any client-visible config and never bake it into an image. The project ID and publishable client key are public by design — the backend deliberately serves them to the browser so Stack can initialize at runtime.

Reverting to local auth

Remove the variables above (or set AUTH_PROVIDER=local) and restart. The UI detects local from the backend at runtime and falls back to the built-in email/password flow — no rebuild required.