Local login is implemented, wired through api, alerting and web, and undiscoverable. No compose file turns it on, the Helm chart sets none of its variables, and no markdown in the repository mentions -seed-admin, LOCAL_AUTH_ENABLED or local login at all. The only way to find it is to read cmd/api/main.go's authorizer switch. Enabling it in docker-compose.yml is not the answer: a plain `docker compose up` has no authentication, and every Phase 0-3 runbook verifies the pipeline with bare curl against /query. Turning login on by default would break the project's own documented verification. So it's an opt-in overlay instead. Four settings have to agree, and only one of them is obviously about login. Each fails differently and none of the failures name the cause: the route 404s, or the browser refuses the request before sending it, or login returns 200 and every later request is anonymous because the cookie was never stored, or the same symptom again from the opposite end because the bundle never attaches it. That is what the new document is mostly for. The Helm chart still has no local-login support. Recorded in the document as a gap rather than papered over. Signed-off-by: John Coffey <[email protected]>
4.0 KiB
Local login
Username and password authentication, served by api itself against the
control-plane Postgres. It is the alternative to Phase 4's SSO
(enterprise-auth, OIDC/SAML) for a deployment that wants a login screen
without an identity provider behind it.
The two are mutually exclusive by construction. cmd/api/main.go picks
one authorizer: ENTERPRISE_AUTH_URL wins if it is set, and only
otherwise does LOCAL_AUTH_ENABLED take effect. With SSO configured,
/auth/* is never registered and local login does not exist.
Off by default, and why
A plain docker compose up has no authentication at all. That is
deliberate rather than an oversight: every Phase 0-3 runbook verifies the
pipeline with bare curl against /query, and those steps only work
against an unauthenticated API. Turning login on globally would break the
project's own documented verification procedure.
So it is an opt-in overlay:
docker compose -f docker-compose.yml -f docker-compose.local-auth.yml up -d --build
--build is not optional. One of the four settings is a Vite build arg
baked into the static bundle, so a restart alone leaves the frontend
disagreeing with the backend.
Creating the first account
There is no sign-up. The first account is an operator action:
docker compose -f docker-compose.yml -f docker-compose.local-auth.yml \
run --rm api -seed-admin
created default admin user:
username: admin
password: <generated>
this password will not be shown again -- save it now.
It creates admin as an owner with a random password, prints it once,
and stores only a bcrypt hash. Losing it means resetting it, not
recovering it. The command is idempotent: if the admin account already
exists it says so and does nothing.
Then sign in at http://localhost:3000/login. Change the password from the account page.
The four settings, and why they must agree
| Setting | Service | What it does |
|---|---|---|
LOCAL_AUTH_ENABLED |
api, alerting |
Registers /auth/*, and swaps WithCORS for WithCredentialedCORS |
CORS_ALLOWED_ORIGIN |
api, alerting |
Must be a literal origin — the default * is refused by browsers for credentialed requests |
LOCAL_AUTH_COOKIE_SECURE |
api |
Defaults to true; the cookie is not stored over plain http://localhost unless this is false |
VITE_LOCAL_AUTH_ENABLED |
web (build arg) |
Without it the bundle never sends credentials: 'include' |
Only the first is obviously about login, and every one of them fails differently:
LOCAL_AUTH_ENABLEDunset — the login page posts to/auth/loginand gets a 404. The route is not registered at all, deliberately, so a deployment with the feature off answers as though it does not exist rather than advertising a disabled feature.CORS_ALLOWED_ORIGINleft at*— the browser refuses the request before it is sent, and the page reports a network failure rather than an HTTP status.LOCAL_AUTH_COOKIE_SECUREleft attrueover HTTP — login returns200and appears to work, then every subsequent request is unauthenticated, because the cookie was never stored.VITE_LOCAL_AUTH_ENABLEDunset — same symptom as the previous one, and from a different cause: the cookie exists but is never attached.
Set LOCAL_AUTH_COOKIE_SECURE back to true for anything served over
HTTPS, and set CORS_ALLOWED_ORIGIN to the real web origin. The values in
the overlay assume http://localhost:3000.
Roles
owner, admin, editor, viewer, from api/authz. Owners manage
everyone; admins may create and delete viewer/editor accounts only,
and cannot reset an owner's password. Two guards prevent a deployment
from becoming unadministrable: the last owner can be neither deleted nor
demoted, and no account can delete itself while signed in.
Not covered by the Helm chart
deploy/helm/cairnobs has no local-login support — it sets none of these
variables. A Kubernetes deployment authenticates via enterprise-auth
SSO or not at all. This is a gap, not a decision.