Roles, Permissions & Multi-Tenancy
Version 1 · Roles/permissions model and an explicit, honest comparison against Keycloak-style multi-tenancy — requested by ClickUp task 86d40a7qe
Historical versionRoles, Permissions & Multi-Tenancy
Written for the "official developer and integration guide" requested in ClickUp task 86d40a7qe, which frames QDBAuth as "similar to Keycloak." This page documents where that comparison holds and where it doesn't — most importantly for multi-tenancy, which QDBAuth does not actually implement the way Keycloak does.
Roles
Every account has exactly one role string (users.role, VARCHAR(20)) plus
an is_admin flag derived from it. There is no separate fine-grained
permission system (no per-action permission grants) — role is the whole
permission model, and consuming apps are expected to interpret the role
string returned to them for their own authorization decisions.
Global roles
Default set: admin, developer, user (ROLE_CHOICES in
apps/auth/users.py). admin sets is_admin=1 and is the only role that
can access QDBAuth's own dashboard (dashboard.require_admin matches the
literal string "ADMIN" after uppercasing — nothing else can match it).
Per-site custom roles
A site can define its own role list instead of the global one
(ROLE_GROUPS in apps/auth/users.py). Currently only TD (Troyen Data)
does: Developer, Support, Dev Lead, Support Lead, Super Admin. TD's
Super Admin is that group's admin_equivalent (sets is_admin=1) but —
critically — still cannot access QDBAuth's own dashboard, because that
check only matches the literal "admin" role, never a site's custom
equivalent. Per-site roles are meant to be consumed by the site itself (via
the role field in /api/verify-2fa/'s response, or user_permissions from
/api/whoami/), not to grant any QDBAuth-level privilege.
role_group_for_sites(approved_sites) resolves which group applies at
creation/edit time: the first granted site with its own entry in
ROLE_GROUPS wins. Known limitation: a user granted two sites that each
define different custom role groups can't have two independent role
values — role is one column. This hasn't come up yet (only one site
customizes roles today) but would need a design decision if a second site
ever adds its own role list.
Where roles are enforced
- QDBAuth's own dashboard:
dashboard.require_admin/require_logindecorators, checked against the session'sdash_permissionsvalue. - Everywhere else: the consuming app receives the role string
(
/api/verify-2fa/'suserobject, or/api/whoami/'suser_permissions) and is responsible for interpreting it. QDBAuth does not gate access to any consuming app's own features — it only vouches for who the person is and what role string they hold.
Multi-tenancy — the actual answer
QDBAuth does not implement multi-tenancy in the Keycloak sense. There is
one global users table, shared across every consuming application — a
person's email is unique across the entire ecosystem, not scoped per
tenant/realm. There's no data isolation between "tenants"; every site's admin
can (in principle) see every user via the same dashboard.
What QDBAuth actually has, that's closest to a Keycloak concept, is the
"site" model (site table + approved_sites) — this maps to Keycloak's
"client" concept (a registered consuming application), not to a
"realm" (an isolated tenant with its own user pool). Concretely:
| Keycloak concept | QDBAuth equivalent | Notes |
|---|---|---|
| Realm (tenant, isolated user pool) | Not implemented | All users are global; no tenant boundary |
| Client (a registered app) | site table entry |
site_name + site_url |
| Client-specific role mapping | ROLE_GROUPS (only for sites that opt in) |
Only TD uses this today |
| Per-client credentials | site_credentials.py (opt-in, new accounts only) |
See Overview |
If genuine tenant isolation (separate user pools per customer/organization) is a real future requirement, that's a substantial architectural change, not a configuration option — flag it as its own project decision rather than assuming today's "site" model already provides it.
Related pages
- Overview — architecture and per-site credentials
- Authentication, MFA & Token Internals — how role strings flow through tokens
- Administrator User Guide — how an admin actually assigns roles/sites when creating a user