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

Multi-tenancy

ScaiDrive is multi-tenant. Every resource — user, group, share, file, folder, ACL, quota, audit event — belongs to a tenant, and tenants cannot see each other. This page covers the tenancy model, how it shows up in the API, and what happens at the edges.

The three levels#

flowchart TD P["Partner (prt_…)<br/><i>managed service provider, optional</i>"] T["Tenant (tnt_…)<br/><i>organization / customer</i>"] U["Users (usr_…)"] G["Groups (grp_…)"] S["Shares (shr_…)"] F["Files (fil_…)"] D["Folders (fld_…)"] P --> T T --> U T --> G T --> S S --> F S --> D
  • Partner — an optional outer layer. A consulting firm that runs ScaiDrive for five customers is a Partner; each customer is a Tenant. If you're running ScaiDrive for a single organization, there's still a Partner record, but you'll rarely interact with it.
  • Tenant — an organization. The practical boundary for data isolation, administration, and billing.
  • User — a person or service account inside a tenant. Identified by usr_.... Users have roles, quotas, and group memberships.
  • Group — a collection of users inside a tenant. Can be share members and ACL principals.
  • Share — a collaboration namespace inside a tenant. The container for files and folders.

Resource IDs are globally unique strings, but they resolve within their tenant. There's no "cross-tenant file" — accessing a file always implies "this tenant's file with this ID."

How tenancy is enforced#

Tenancy is checked in three places:

  1. Token. The JWT's tenant_id claim pins every request to one tenant. You cannot present a token for Tenant A and access Tenant B's data.
  2. Query layer. Every database query filters by tenant_id. The service layer takes current_user.tenant_id as a hard requirement; it's not possible to ask "give me this file regardless of tenant."
  3. ACL layer. ACEs grant rights to principals (users, groups) that belong to the same tenant as the resource. Cross-tenant principals are rejected at write time.

Result: a request authenticated as a Tenant A user cannot access Tenant B resources, even if they know the IDs.

Resolving a user's tenant#

Clients rarely need to think about tenants — the JWT pins it automatically. To verify:

bash
1
2
curl -H "Authorization: Bearer $SCAIDRIVE_TOKEN" \
     $SCAIDRIVE_URL/api/v1/users/me
python
1
2
3
4
5
6
resp = httpx.get(
    f"{url}/api/v1/users/me",
    headers={"Authorization": f"Bearer {token}"},
)
user = resp.json()
print(user["tenant_id"], user["partner_id"])
typescript
1
2
3
4
5
const resp = await fetch(`${url}/api/v1/users/me`, {
  headers: { Authorization: `Bearer ${token}` },
});
const user = await resp.json();
console.log(user.tenant_id, user.partner_id);

Users in multiple tenants#

A human can have multiple ScaiKey accounts, one per tenant. They log in to each separately and get a different JWT for each. From the server's perspective, these are entirely separate principals — there's no cross-tenant linking.

If you're building a UI that lets a user switch tenants, the switch is a re-login against ScaiKey with a different tenant context, not an in-app operation.

Partner and super admin operations#

Most tenant-level operations are scoped to the tenant in the JWT. A few are cross-tenant:

Partner admin (partner:admin scope) can view and manage quotas for every tenant under their partner — see Quotas. They cannot view content, only quotas and metadata.

Super admin (* or platform:admin scope) can do anything on any tenant. Reserved for platform operators. Super-admin actions are recorded in the audit log of every affected tenant.

Neither role bypasses ACLs on file contents — you cannot read a file you don't have READ permission on, even as super admin, unless you first grant yourself that permission (which is auditable).

Quotas across the hierarchy#

Quotas apply at every level:

  • Partner quota — total storage for all tenants under a partner.
  • Tenant quota — total storage for one tenant.
  • User quota — per-user allocation within a tenant.
  • Group quota — aggregate allocation for a group.
  • Share quota — per-share cap.

Any request that would push usage above any applicable quota fails with 507 QUOTA_EXCEEDED. The error identifies which quota was exceeded.

See Quotas for configuration.

Tenant isolation at the audit level#

Every audit event is tagged with its tenant. The audit log of Tenant A does not contain events from Tenant B, even if a partner admin performed them. Partner-admin cross-tenant actions appear in both the tenant's log (as "performed by [partner admin]") and a separate cross-tenant log available only to partner and super admins.

What's next#

Updated 2026-05-18 15:04:10 View source (.md) rev 2