---
title: Multi-tenancy
path: core-concepts/multi-tenancy
status: published
---

# Multi-tenancy

ScaiVault has a three-level tenancy model inherited from the ScaiLabs platform: **partners**, **tenants**, **identities**. Every secret, every policy, every audit entry is scoped to a tenant. Every tenant belongs to one partner.

## The three levels

**Partner.** Top-level account. Usually a company, a platform operator, or a reseller. Has one or more tenants.

**Tenant.** A workspace within a partner. Typically corresponds to an environment (dev/staging/prod) or a customer (for platforms). Has its own secrets, policies, users.

**Identity.** A user, service account, or group within a tenant. Identities come from [ScaiKey](https://scaikey.scailabs.ai) — ScaiVault does not manage users itself.

```mermaid
graph TB
    P[Partner: ptn_acme]
    T1[Tenant: tnt_acme_prod]
    T2[Tenant: tnt_acme_dev]
    T3[Tenant: tnt_acme_shared]
    U1[user: alice@acme.example]
    U2[user: bob@acme.example]
    SA[service_account: reporting-service]
    G[group: sre]
    S1[secret: environments/production/db/password]
    S2[secret: environments/production/salesforce/oauth]
    S3[secret: environments/dev/db/password]

    P --> T1
    P --> T2
    P --> T3
    T1 --> U1
    T1 --> U2
    T1 --> SA
    T1 --> G
    T1 --> S1
    T1 --> S2
    T2 --> S3
```

## Tenant resolution

Every request is scoped to exactly one tenant. The tenant comes from one of three places, in priority order:

1. **Explicit path prefix** — `/v1/t/{tenant_id}/...`. Requires the caller's token to have partner-admin privileges and the target tenant to belong to the caller's partner.
2. **`X-Tenant-ID` header** — equivalent to the path prefix. Same auth requirements.
3. **Token's `tenant_id` claim** — the default. Your token is bound to one tenant; all your requests act as that tenant.

If the requested tenant doesn't belong to your partner, you get `403 access_denied`. If the tenant doesn't exist, `404 tenant_not_found`.

## Tenant-scoped paths

The common case. Your token's `tenant_id` claim determines scope automatically.

```bash
GET /v1/secrets/app/db/password
```

Resolves to: "read `app/db/password` in the tenant identified by my token."

Tenants cannot see each other's secrets. A secret at `app/db/password` in `tnt_acme_prod` and one at the same path in `tnt_acme_dev` are entirely separate rows — same path, different tenants.

## Partner-scoped paths

Sometimes you want a secret visible to every tenant under a partner — a shared trust anchor, a partner-wide default config, a central webhook-signing key. Use the `/v1/partner/secrets/*` prefix:

```bash
curl -X PUT https://scaivault.scailabs.ai/v1/partner/secrets/shared/webhook-signing-key \
  -H "Authorization: Bearer $PARTNER_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"data": {"key": "..."}, "secret_type": "kv"}'
```

Every tenant under `ptn_acme` can read `shared/webhook-signing-key`, but only partner admins can write. Partner secrets show up in tenant-scoped lists with a `"scope": "partner"` marker.

## Explicit tenant access

Partner admins sometimes need to act as a specific tenant — debugging, bulk updates, automated provisioning. The `/v1/t/{tenant_id}/` prefix does this:

```bash
GET /v1/t/tnt_acme_prod/secrets/app/db/password
Authorization: Bearer $PARTNER_ADMIN_TOKEN
```

This reads from `tnt_acme_prod` as if you were a member. The audit log records the acting identity (the partner admin) *and* the target tenant. Use this for operator tasks, not for steady-state application traffic.

All endpoints (`/v1/secrets/*`, `/v1/policies/*`, `/v1/audit/*`, etc.) are available under the `/v1/t/{tenant_id}/` prefix with identical semantics.

## Roles

ScaiKey defines a small set of admin roles that ScaiVault respects:

| Role | Scope | What it can do |
|------|-------|----------------|
| `super_admin` | Platform | Manage any partner or tenant. Reserved for ScaiLabs staff. |
| `partner_admin` | Partner | Manage tenants under the partner, read/write partner-scoped secrets, act cross-tenant. |
| `tenant_admin` | Tenant | Manage policies, service accounts, rotation policies within one tenant. |

Roles are *additive* — a `partner_admin` is implicitly a `tenant_admin` for every tenant under their partner. A `super_admin` is everything.

Non-admin identities (regular users, service accounts, groups) get their access from **policies**, not roles. A tenant user doesn't "have tenant-admin access" unless the policies bound to them say so. See [Policies and Permissions](./policies-and-permissions).

## Cross-tenant sharing (what to do instead)

Tenants cannot directly read each other's secrets. If you need two tenants to share a value:

- **Is it really tenant-specific?** Probably yes. Store it twice.
- **Is it partner-wide?** Use `/v1/partner/secrets/*`.
- **Is it a live copy that must stay in sync?** Use [Federation](../advanced/federation) with one tenant as the source of truth.
- **Is this a one-off migration?** Partner admin reads from tenant A, writes to tenant B, records the transfer in audit.

We deliberately don't provide "grant tenant B read access to tenant A's secret X" — it breaks the isolation contract that makes tenants meaningful.

## Identity types

| Type | Example ID | When to use |
|------|-----------|-------------|
| `user` | `user:alice@acme.example` | A human in the admin UI or CLI |
| `service_account` | `sa:reporting-service` | A service making API calls |
| `group` | `group:sre` | A set of users, bound via policies |

Policies bind to any of these. A binding on a `group` effectively grants access to every user in that group — group membership is resolved at request time from the cached ScaiKey data.

## Impersonation and on-behalf-of

Service accounts can be configured in ScaiKey to "act on behalf of" a user. When the service account authenticates, the token's `act` claim names the user; ScaiVault uses the service account's scopes but credits the user in the audit log. This is useful for user-facing services that proxy calls to ScaiVault — the audit log tells you which *human* triggered each read.

## What's next

- [Policies and Permissions](./policies-and-permissions) — how paths, identities, and rules compose.
- [Authentication](../getting-started/authentication) — tokens and the tenant_id claim.
- [Identity Reference](../reference/identity) — endpoints for the identity cache.
