OutlabsAuth UI
OutlabsAuth UI is an optional sidecar admin console — a static single-page
app built with Nuxt 4 and Nuxt UI 4, deployed separately from your API. It is
not part of the Python package, and it does not ship a second auth stack.
One build serves any FastAPI host that has OutlabsAuth mounted, using the same
routers your product already exposes; each deployment names its API in a
runtime app-config.json.
We maintain it ourselves and use it day-to-day: it is the fastest way to see and operate what is going on in an OutlabsAuth-backed system — users, roles, entities, keys, sessions, audit, and more — without building that console from scratch.
VITE_*
environment variables and the 5173 dev port no longer apply.Why it exists
Sidecar, not a product UI
Point it at any instance that mounts OutlabsAuth — local examples, staging, or production. Your customers still get your screens; this console is for operators and implementers.
Full gamut of features
When the matching routers are mounted, you get the same surface the library exposes: invites, roles, permissions, ABAC, entities, memberships, API keys, sessions, audit search, account self-service, passwordless entry flows, and OAuth link/unlink where enabled.
Visualise the system
Browse the org tree, inspect memberships, search audit events, check active sessions, and watch activity signals on users and entities — useful while integrating and debugging, not only for “admin CRUD.”
Reference for your own UI
The repo is a working example of how to consume /auth/config, permission
gates, and the management APIs. Steal patterns; you do not have to ship this
SPA to end users.
What you can do in the console
A workspace appears only when the backend mounts its router (listed in
mounted_surfaces from GET {authApiPrefix}/auth/config), the matching
feature is on, and the signed-in admin holds the permission it needs, so a
delegated admin sees what they may do and nothing else.
| Workspace | Where | What it is for |
|---|---|---|
| Dashboard | Sidebar | Capability snapshot and shortcuts into visible workspaces |
| Users | Sidebar · Directory | Invite / create, status, password reset, roles, memberships, sessions, personal keys, orphaned users, history, permission checks |
| Entities | Sidebar · Directory | Enterprise org tree — create, move, members, local roles, activity |
| Roles | Sidebar · Access control | Role definitions, their permissions, ABAC conditions when enabled |
| Permissions | Sidebar · Access control | Permission catalog |
| Service accounts | Sidebar · Integrations | System integration principals and their API keys |
| Audit | Sidebar · Monitoring | Cross-user event search with before/after/metadata inspection |
| Settings | Sidebar (admins) | Server capabilities from /auth/config plus mutable entity types |
| Account | User menu | Profile and phone verification, password and own sessions, connected accounts, own access |
| My API keys | User menu | The signed-in user's personal API keys |
The sign-in side offers every method the backend advertises and the deployment
allows: password, magic link, e-mail and phone codes (WhatsApp, SMS), OAuth
providers, self-signup, recovery, and accepting an invitation. A method shows
only when both the backend (/auth/config) and the deployment's authUi
settings allow it.
authUi.signup: true in the template). For an
invite-only operator console, set "signup": false in authUi. That only hides
the console's link and page: POST {authApiPrefix}/auth/register stays mounted
with get_auth_router, so block registration in your host as well if it must
be closed.How it connects
Your FastAPI app (any host)
└── OutlabsAuth routers under a stable prefix (/v1, /iam, …)
↑
│ apiBaseUrl + authApiPrefix
│
OutlabsAuth UI (static site, separate deploy)
Configure two values, plus a third when the backend registers frontend profiles:
| Field | Meaning |
|---|---|
apiBaseUrl | Origin of the FastAPI app (no trailing slash). Must be https in a deployment; plain http is accepted only for localhost |
authApiPrefix | Parent of /auth, starting with / — e.g. /v1 when you mount /v1/auth, / when you mount /auth |
frontendProfileKey | The frontend profile the console signs in as (sent as app). Must name a profile the backend registers; omit it for a backend without profiles. An unknown key makes every sign-in fail with wrong_application |
With authApiPrefix: "/v1", the UI calls /v1/auth/config, /v1/auth/login,
/v1/users, /v1/roles, and so on. It adapts navigation for SimpleRBAC vs
EnterpriseRBAC from that config snapshot (entity hierarchy, context-aware
roles, activity tracking, …).
get_auth_router(..., prefix="/v1/auth"), set authApiPrefix to
/v1, not/v1/auth.The console targets the outlabs-auth.api/v1 API contract that /auth/config
reports as api_contract_version (the Settings workspace shows it). Its release
gate runs against the outlabs-auth example hosts at the version pinned in the UI
repo's README.
Quick start
Clone and install
Requires Bun 1.3.3+ and Node.js 22.18+.
git clone https://github.com/outlabsio/OutlabsAuthUI.git
cd OutlabsAuthUI
bun install
cp public/app-config.template.json public/app-config.json
Point at your API
{
"apiBaseUrl": "http://localhost:8004",
"authApiPrefix": "/v1",
"frontendProfileKey": "console",
"appName": "OutlabsAuth UI",
"appSubtitle": "Shared auth admin console",
"authBrand": "OutlabsAuth",
"authLogoUrl": "/brand/outlabs-auth-logo.svg",
"signInDescription": "Sign in against the configured auth backend to access this console.",
"authUi": {
"signup": true,
"identifier": "email-or-phone",
"defaultCountry": "AR",
"channels": ["whatsapp", "sms"],
"oauthProviders": [],
"magicLink": true
}
}
| Example host | API port | Suggested config |
|---|---|---|
examples/simple_rbac | 8003 | apiBaseUrl: http://localhost:8003, authApiPrefix: /v1 |
examples/enterprise_rbac | 8004 | apiBaseUrl: http://localhost:8004, authApiPrefix: /v1 |
frontendProfileKey: "console" matches a profile the EnterpriseRBAC example
registers. Remove it for a backend that registers no frontend profiles (the
SimpleRBAC example registers none), or set it to the key your host registers
for the console. authUi chooses which
sign-in methods the console offers; set "signup": false for an invite-only
console.
Run the UI
bun run dev
The dev server runs on http://localhost:3000; both example hosts already
allow that origin (and :3001) in their CORS settings. Sign in with a bootstrap
or seeded admin from the host app.
Config precedence: a deployed build reads only an inline
window.__OUTLABS_AUTH_UI_CONFIG__ (which wins) and the served
/app-config.json; a missing or invalid config stops the console on a
configuration error. The dev server also reads NUXT_PUBLIC_* variables, below
the file, and falls back to http://localhost:8004 with /v1. Every key,
including the authUi sign-in options, is documented in the UI repo's
configuration section.
What to mount on the backend
Minimum for login: get_auth_router (and GET /auth/config comes with it).
For a useful admin console, mount the admin UI–friendly sets in Routers & Prefixes — users, roles, permissions, API keys, and (for Enterprise) entities / memberships / audit as needed.
mounted_surfaces), a feature flag off on the backend, or a signed-in
account without the permission the workspace needs — not a broken SPA.Simple vs Enterprise behaviour
The same SPA serves both presets. Invite and membership forms change with the backend:
- SimpleRBAC — no entity scope on invites; selected
role_idsbecome direct account role memberships. - EnterpriseRBAC — entity hierarchy and memberships appear when advertised;
invites can attach roles through an entity membership when
entity_idis supplied.
Building your own UI instead
You do not have to deploy OutlabsAuth UI. Many products keep customer-facing auth screens in-house and only use this console internally.
If you do build your own:
- Call
GET {prefix}/auth/configand drive feature UI from that payload:featuressays what the preset supports,mounted_surfacessays which routers the host actually included. - Reuse the same permission names the library enforces (
user:read, …). - Treat the OutlabsAuth UI repo as a worked example, not a required
dependency:
app/utils/capabilities.tsgates workspaces on surfaces, features and permissions,app/queries/holds the API layer (Pinia Colada), andapp/schemas/the Zod form rules.
Deploy notes
- One build, per-deployment config.
bun run generateproduces a static site in.output/publicwith a hash-based Content-Security-Policy. Each deployment keeps its ownapp-config.jsonoutside the repository; the deploy preflight validates it, stages it, and pins the CSPconnect-srcto its API. A host that injectswindow.__OUTLABS_AUTH_UI_CONFIG__inline must add that script's hash toscript-src. - Hosting. Serve the console at the root of its own hostname (sub-paths are
not supported). The repository deploys to Cloudflare Workers static assets
(
bun run deploy:cloudflare --config <app-config.json> --env <name>); another host must reproduce the generated_headersand the routing rules inwrangler.toml. - Release gate. There is no hosted CI.
bun run release:checkruns typecheck, lint, unit tests and the full Playwright suite on the static build against seeded EnterpriseRBAC and SimpleRBAC example hosts, and the Cloudflare deploy accepts only a commit with a recent passing record. - Backend settings. CORS must allow the console origin exactly, with
credentials. With
frontendProfileKey, the profile's public origin must be the console, so emailed reset, invitation, magic-link and code links open it. OAuth works only when the console and the API share a site (one registrable domain, e.g.console.example.comandauth.example.com), with the success, error and associate redirects at/auth/oauth/callback,/auth/loginand/app/account. - No host secrets. OAuth, SMS and email credentials stay on the backend; the console only uses the public auth API.
The full per-deployment checklist is in the UI repo's PRODUCTION.md.
Known limitations
What is built, partial or missing for each backend capability, with the tests that prove it, is tracked in the UI repo's CAPABILITIES.md; the outlabs-auth changes it waits on are listed in PRODUCTION.md.
Related
- Routers & Prefixes — what to mount
- Getting Started — wire the library first
- Sessions & Audit — backend contracts the Audit workspace uses
- API Keys — personal vs system integration keys
- OutlabsAuthUI on GitHub