Self-hosted Menace Voice ships with a built-in local authentication provider (email + password, backed by a signed JWT). This is the default and needs no external service.
To offer social logins (Google and other providers), 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 local by default. When the deployment .env contains a Hexclave/Stack project id and secret server key, the API enables stack automatically (AUTH_PROVIDER=local still forces local). 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#
- The backend reads
AUTH_PROVIDERand the Stack settings from its environment. - When
AUTH_PROVIDER=stack,/api/v1/healthreturns the public Stack client config (project id + publishable client key). - The UI fetches that at runtime and initializes the Stack SDK in the browser.
- 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:
| Value | Sensitivity |
|---|---|
| Project ID | Public |
| Publishable client key | Public (safe to expose in the browser) |
| Secret server key | Secret — keep server-side only |
| API base URL | Public. For Stack's hosted service this is https://api.stack-auth.com |
Step 2 — Set them in the deployment .env#
Put the values in the .env next to docker-compose.yaml (the file setup_remote.sh / setup_local.sh created — not api/.env, which only applies to local uvicorn). Compose interpolates that file into both the api and ui containers; you do not need to edit docker-compose.yaml.
Legacy STACK_AUTH_PROJECT_ID / STACK_SECRET_SERVER_KEY names still work.
The UI does not need the project id or publishable client key in its own env — it receives those from the backend at runtime via /api/v1/health. The secret server key is passed to ui as well because SSR pages and /handler/* call Stack server-side.
Step 3 — Restart and verify#
Recreate the containers so they pick up the new environment:
Confirm the backend reports the active provider and the public client config:
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#
| Variable | Service | Secret | Notes |
|---|---|---|---|
AUTH_PROVIDER | api | — | stack or local. Unset + project id + secret enables stack. local always wins |
HEXCLAVE_PROJECT_ID / STACK_AUTH_PROJECT_ID | api | No | Project ID; served to the UI at runtime |
STACK_PUBLISHABLE_CLIENT_KEY | api | No | Publishable key; served to the UI at runtime. Optional for newer Hexclave projects |
HEXCLAVE_SECRET_SERVER_KEY / STACK_SECRET_SERVER_KEY | api + ui | Yes | Server-side only — never exposed to the browser |
STACK_AUTH_API_URL / HEXCLAVE_API_URL | api | No | REST API base URL. Defaults to https://api.hexclave.com |
HEXCLAVE_SECRET_SERVER_KEY / 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.