Repository navigation
Auth in development
How login works locally: the dev username/password flow, seeded roles, optional real OIDC, and the compatibility routes. Status: current. Wire contract: Auth API.
| Flow | When | Backend | Frontend |
|---|---|---|---|
| Dev login | Local development | POST /v1/auth/dev-login |
button when VITE_APP_FEDERATED_AUTH=false
|
| OIDC | Production / federated testing |
GET /v1/auth/login → Sigarra → /callback
|
link when VITE_APP_FEDERATED_AUTH=true
|
Both end with the same opaque session cookie and the same Session row. There is no “dev session”.
The default. LoginButton posts without a body; the backend authenticates with the account in
apps/backend/.env:
DEV_LOGIN_ENABLED=true
SIGARRA_USERNAME=up202100000
SIGARRA_PASSWORD=…- If the request carries
{ username, password }, those are used instead. -
DEV_LOGIN_ENABLEDis forced off whenNODE_ENV=production; the route then answers404 not-found. - No configured account and no body →
503 dev-login-not-configured. - Wrong credentials →
401 invalid-credentials. - On success the user is upserted by NMEC, so the seeded placeholder name is replaced by the real one.
The credentials are real SIGARRA credentials. Use your own; do not commit them.
Roles are seeded, never assigned by login:
ADMIN_UP=202207150 # your NMEC (up prefix optional)
ADMIN_ROLE=ADMIN # USER | ADMIN | SUPERUSERThen re-seed:
cd apps/backend
bun run db:seed:demodb:seed:demo creates that account with the role and, for ADMIN/SUPERUSER, full
AdminCourse/AdminOccurrence scope. ADMIN_ROLE=USER creates the account with no admin scope.
Logging in as that NMEC does not elevate it; the role comes from the row.
Re-seeding truncates every table. Do it before you have data you care about.
To test the production flow:
# apps/backend/.env
OIDC_CLIENT_ID=…
OIDC_CLIENT_SECRET=…
OIDC_REDIRECT_URI=http://localhost:3000/v1/auth/callback
FRONTEND_URL=http://localhost:3100
ALLOWED_ORIGINS=http://localhost:3100
COOKIE_SECURE=false# apps/frontend/.env
VITE_APP_FEDERATED_AUTH=true- Register
http://localhost:3000/v1/auth/callbackas an allowed redirect URI on the Keycloak client. - Restart both dev servers.
- Click Entrar → Sigarra → back to the callback → redirect to
FRONTEND_URL.
Notes:
- No
/etc/hostsentry is required forlocalhost; use the redirect URI registered on the client. -
FRONTEND_URLis both the default post-login destination and thereturn_toallowlist. - Without client id/secret the routes answer
503 oidc-not-configured; the rest of the app still boots. - The callback sets
HttpOnly,SameSite=Laxcookies;Secureis off locally because the dev origin is HTTP.
For the un-migrated frontend, mounted at the root (not under /v1):
| Route | Purpose |
|---|---|
GET /oidc-auth/authenticate/ |
legacy login link → /v1/auth/login
|
POST /oidc-auth/logout/ |
legacy logout; ignores the CSRF header |
GET /auth/info/ |
legacy session shape (username, eligible_exchange, is_admin) |
POST /sigarra_login/ |
legacy dev login; same gating as /v1/auth/dev-login
|
/auth/info/ always reports eligible_exchange: false on the new backend. They are 🔁 aliases, not a
second auth system.
# dev login; store cookies in a jar
curl -i -c /tmp/tts-cookies -X POST http://localhost:3000/v1/auth/dev-login
# who am I?
curl -s -b /tmp/tts-cookies http://localhost:3000/v1/auth/me
# catalog requires the session
curl -s -b /tmp/tts-cookies http://localhost:3000/v1/faculties
curl -s http://localhost:3000/v1/faculties # → 401The session cookie is opaque and HttpOnly; do not try to read it from JavaScript.
| Symptom | Cause / fix |
|---|---|
404 on dev login |
DEV_LOGIN_ENABLED=false, or NODE_ENV=production
|
503 dev-login-not-configured |
no request body and no SIGARRA_USERNAME/PASSWORD
|
401 invalid-credentials |
wrong SIGARRA username/password |
| Button opens OIDC instead of dev login |
VITE_APP_FEDERATED_AUTH=true in the frontend .env
|
503 oidc-not-configured |
missing OIDC_CLIENT_ID / OIDC_CLIENT_SECRET
|
400 oidc-state-mismatch |
stale/blocked oidc_state cookie, or two tabs mid-flow |
Login succeeds, /me says anonymous |
cookie not sent: wrong origin, Secure on HTTP, or CORS |
| Logged in but no admin UI | role is USER, or you logged in as another NMEC |
After changing auth env vars, restart the backend (and rebuild the frontend if a VITE_* value
changed).
- Auth API — routes, status codes, legacy shapes
- Auth & sessions — OIDC/session architecture and security limits
- Environments — full env matrix
- Local setup — first run
- Troubleshooting — broader setup failures
Last verified: 2026-11-02