Tenants and grants

Explicit tenant and grant management for platform backends: pre-create tenants, tenant-wide vs runtime-scoped grants, authorize without issuing, and revoke.

The one-shot path covers most platforms: createMountTicket auto-creates a missing tenant and a runtime-scoped grant on first use, so you never manage either explicitly. This page is for when you need more than that happy path, and the table below is the trigger list. For what tenants, grants, and tickets are, see Multi-tenancy model.

When you need explicit calls

You want toUse
Link a tenant to your own customer id, or attach metadatacreateTenant
Let every runtime under a tenant mount a workspace (one grant, many runtimes)tenant-wide createAccessGrant
Authorize a runtime now, issue the ticket later (or many over time)createAccessGrant, then createMountTicket per task
Expire access automaticallyttlSeconds on the grant

Otherwise the one-shot createMountTicket is enough.

Create a tenant explicitly

const tenant = await artifacts.platform.createTenant('acme', {
  externalId: 'cust_42',          // your own customer id
  metadata: { plan: 'pro' },
});

externalId links the Tonbo tenant to your customer record; metadata is free-form. The slug must match ^[a-z0-9][a-z0-9-]{0,62}$. Creating a tenant that already exists returns a conflict; the one-shot path reuses an existing tenant instead of failing.

Grant access explicitly

A grant is the durable authorization edge. Scope it to one runtime, or make it tenant-wide:

// Runtime-scoped: only this runtime id can mount, read-only.
await artifacts.platform.createAccessGrant('<your-handle>/my-workspace', {
  tenantSlug: 'acme',
  runtimeId: 'task-123',
  mode: 'ro',
  ttlSeconds: 3600,        // optional auto-expiry
});

// Tenant-wide: omit runtimeId. Any runtime under acme can mount.
await artifacts.platform.createAccessGrant('<your-handle>/my-workspace', {
  tenantSlug: 'acme',
  mode: 'rw',
});

With a grant in place you can issue tickets repeatedly for that scope without re-authorizing each task. A pre-existing ro grant is never widened to rw by a later ticket request.

Revoke

// Precise: one grant whose id you tracked.
await artifacts.platform.revokeAccessGrant(grantId);

// By scope: all grants for a tenant + runtime (tenantSlug is required).
await artifacts.platform.revokeAccessGrants({ tenantSlug: 'acme', runtimeId: 'task-123' });

// Everything under a tenant (the customer churned): tears down the tenant and all its grants and sessions.
await artifacts.platform.deleteTenant('acme');

Revocation propagates within about one second; a live mount starts erroring on the next syscall. See Temporary mount credentials for session lifetime and the full authorization reference.