Tenants and Users
ScaiDNS is multi-tenant from the ground up. Every zone belongs to a tenant, every user belongs to a tenant, and most API calls operate within a tenant context.
Identities are owned by ScaiKey, the ScaiLabs identity platform. ScaiDNS is a subscriber to ScaiKey events and maintains a local cache for authorization and audit.
The hierarchy#
Three levels, mirrored from ScaiKey:
Partner. The top-level org. In single-org deployments, there's one partner. In MSP scenarios, a partner represents an operator serving many customers.
Tenant. A customer, department, or project inside a partner. Zones, API keys, role assignments, and audit logs scope to a tenant.
User. An individual human identity. A user belongs to one primary tenant but can be granted access to others (see Permissions and Access).
Group. Collections of users within a tenant. Groups can carry role assignments and own API keys, making them the primary tool for "give this team access to these zones."
Where identities live#
Tenants, users, and groups are created in ScaiKey. Not in ScaiDNS. If you need to add a user, you do it in ScaiKey's admin UI (or ScaiDNS proxies to ScaiKey via POST /api/v1/admin/users).
ScaiDNS maintains a read-mostly local cache with:
- User profile (email, name, status)
- Group membership
- Tenant slug, name, and status
- Mapping from ScaiKey IDs (
usr_...,tnt_...) to internal UUIDs
This cache is updated in two ways:
1. Webhooks#
ScaiKey sends HMAC-signed events on every identity change:
user.created,user.updated,user.deletedgroup.created,group.updated,group.deleted,group.member_added,group.member_removedtenant.created,tenant.updated,tenant.deletedpartner.*application.user_assigned,application.user_unassigned
The webhook endpoint is POST /api/v1/webhooks/scaikey. See Webhooks Deep Dive for signature verification and event shapes.
Webhooks need to be configured on both sides:
- ScaiKey's admin UI: point the webhook URL at your ScaiDNS instance and set the signing secret.
- ScaiDNS's
.env:SCAIKEY_WEBHOOK_SECRET— the same secret, used for signature verification.
2. Periodic sync#
A CLI command pulls the full state from ScaiKey:
1 2 | |
Run on initial setup and if webhooks were missed for some reason. A scheduled daily sync is a reasonable belt-and-braces practice.
Application assignment#
ScaiDNS is registered in ScaiKey as an application (with an ID like app_abc123). Only users and groups assigned to the ScaiDNS application receive user.* and group.* webhooks, and are returned by client.applications.get_effective_users(app_id).
To give a user access to ScaiDNS:
- Assign them (or a group they belong to) to the ScaiDNS application in ScaiKey.
- ScaiKey sends
application.user_assigned→ ScaiDNS upserts the user locally. - Assign them a role or access grant in ScaiDNS (see Permissions and Access).
Tenant context#
Every API request resolves to a tenant. ScaiDNS determines it in this order:
- API keys are bound to the tenant of their owning user or group at creation time.
- JWTs carry
tenant_id(a ScaiKey tenant ID) in their claims. ScaiDNS resolves this to the internal tenant UUID on each request via tenant-resolution middleware.
The resolved tenant ID is available on the CurrentUser context object as internal_tenant_id. It's what scopes all list/read/write operations.
A user can belong to multiple tenants in ScaiKey; which one they act as is determined by the JWT claim they authenticated with. Tenant switching is a ScaiKey concern, not a ScaiDNS one.
Platform admins#
Some users transcend tenants. A platform admin can read and write across every tenant, manage the partner/tenant list, edit platform configuration, and see the global audit log.
Platform admin status comes from one of:
- A claim in the JWT (
roles: ["platform_admin"]orscopes: ["platform:admin"]), set by ScaiKey. - A local role assignment in ScaiDNS:
role_name = "platform_admin"atscope = "platform"in theuser_rolestable.
Normal users and tenant admins never bypass tenant scoping.
Common operations#
| I want to... | Do this |
|---|---|
| Add a user to ScaiDNS | Create in ScaiKey, assign to the ScaiDNS application |
| Give a user access to zones | Assign a role via POST /api/v1/roles/users/{user_id} |
| Give a team access to specific zones only | Create an access grant via POST /api/v1/domains/{id}/access-grants |
| Check what a user can do | GET /api/v1/roles/users/{user_id}/permissions |
| See who changed what | GET /api/v1/admin/audit-logs (tenant-scoped for tenant admins) |
What's next#
- Permissions and Access — role hierarchy and access grants.
- Webhooks Deep Dive — syncing identity changes.
- Users, Groups, and Roles — the endpoint reference.