Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Models Tools & Services
Solutions
Organisations Developers Internet Service Providers Managed Service Providers AI-in-a-Box
Resources
Support Documentation Blog Downloads
Company
About Research Careers Investment Opportunities Contact
Log in

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:

flowchart TB P["Partner<br/>(e.g., ScaiLabs, Acme MSP)"] T["Tenant<br/>(e.g., BBinfra NL, customer-42)"] U["User<br/>(e.g., mbi@bbinfra.net)"] P --> T T --> U

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.deleted
  • group.created, group.updated, group.deleted, group.member_added, group.member_removed
  • tenant.created, tenant.updated, tenant.deleted
  • partner.*
  • 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:

bash
1
2
scaidns sync                  # Full sync (partners, tenants, users, groups)
scaidns sync --users-only     # Only users assigned to the ScaiDNS application

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:

  1. Assign them (or a group they belong to) to the ScaiDNS application in ScaiKey.
  2. ScaiKey sends application.user_assigned → ScaiDNS upserts the user locally.
  3. 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:

  1. API keys are bound to the tenant of their owning user or group at creation time.
  2. 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"] or scopes: ["platform:admin"]), set by ScaiKey.
  • A local role assignment in ScaiDNS: role_name = "platform_admin" at scope = "platform" in the user_roles table.

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#

Updated 2026-05-17 23:58:51 View source (.md) rev 2