Appearance
Multi-tenancy
Authara isolates many companies/products in a single deployment. This is the backbone of using one install across all your products.
The model
A tenant is a fully isolated identity space. Each tenant has:
- Its own Postgres role and row-level security (RLS) — a tenant's queries physically cannot read another tenant's rows. Isolation is enforced at the database.
- Its own OIDC issuer and signing keys — a token minted for tenant A is rejected by tenant B.
- Its own Management API (scoped resource indicator).
- Its own sign-in experience, branding, connectors, users, roles, organizations, webhooks, SSO, and audit logs.
There's a special admin tenant (the control plane) plus a default tenant; real customer tenants sit alongside them, each isolated.
Tenants vs. organizations
Tenants are hard isolation (own DB role + RLS + issuer + console) — use them to separate companies/products. Organizations are lightweight groups inside a single tenant (members/roles/ branding, no separate console) — use them for B2B sub-groups within one tenant, not to separate customers.
Why it's safe to host many products
At request time Authara resolves the tenant from the host/path, connects to Postgres as that tenant's role, and every query is confined by RLS to that tenant. Caches and connection pools are per-tenant. Hosting many products on one install does not risk cross-tenant data leakage — the isolation is structural.
Operator rule
Never run tenant business queries on the shared/owner DB pool (it bypasses RLS). The shared pool is only for control-plane operations (creating roles/tenants).
Creating a tenant
Today, tenant provisioning is done through the CLI seed path (createTenant()), which creates the tenant's Postgres role, the tenants row, and seeds it.
Runtime provisioning API is planned
A runtime POST/GET/DELETE /api/tenants control plane (create tenant → invite tenant-admin → scoped console) is on the roadmap, along with per-tenant console serving and cross-tenant Management-API authorization. Until then, a super-admin provisions tenants through the seed/CLI path.
Tenant administration
- Each tenant is administered through the admin console, scoped to that tenant.
- Who can administer a tenant is modeled by an organization in the admin tenant named
t-{tenantId}with roles Admin and Collaborator. A user is authorized into a tenant by their membership + role. - Keep super-admin (provisions tenants, runs the control plane) and tenant-admin (manages only their own tenant) as distinct scopes.
Custom domains (planned)
The engine already maps host → tenant. To give each tenant its own host (login.customer.com), use subdomain-based multi-tenancy (ENDPOINT=https://*.host) and provision TLS/DNS at your proxy. Reserve admin/default and the admin host so a customer can't shadow the control plane.
Best practices
- One product = one tenant so each product gets a full, isolated console.
- Verify isolation after provisioning: two tenants, each admin sees only their own data; confirm cross-tenant reads are blocked at the DB (they are, via RLS).
- Least privilege at the DB: the runtime app should not own the tables; consider
FORCE ROW LEVEL SECURITY. - Audit-log control-plane actions (tenant create/suspend/delete, admin invites).