Skip to content

Multi-tenant SaaS

SaaS workspaces map one-to-one to Pore tenants. Each workspace has its own tenant; each API key is scoped to one tenant.

On workspace create, provision a Pore tenant and store the tenant id on the workspace row:

const { tenantId } = await pore.admin.tenants.create({
displayName: workspace.name,
});
await db.workspace.update({
where: { id: workspace.id },
data: { poreTenantId: tenantId },
});

When you issue an API key for this workspace, scope it to the tenant. The SDK instance you construct for workspace requests uses that key.

Model workspace membership as a group:

(user:alice, member, workspace:acme)

Then grant roles to the workspace:

(workspace:acme, editor, document:42)

Alice inherits editor on document:42 through her membership.

A user may be a member of many workspaces. Each workspace is a separate tenant with its own grant graph. Your application routes the user’s request to the right tenant’s API key before calling check.

Revoke the member tuple:

revoke (user:alice, member, workspace:acme)

Every grant alice inherited through that membership evaporates on the next check call. No cascade delete needed.