Multi-tenancy and auth
ScaiFlow is multi-tenant from the ground up. Every flow, every catalog package, every credential, every event is scoped to a tenant. Auth flows through ScaiKey.
Auth flows#
Canvas → backend (OIDC + PKCE)#
The single ScaiKey WEB client is shared by canvas (PKCE, browser-side) and backend (BFF, server-side). The client_secret never reaches the browser. Audience for issued tokens is client_id (ScaiKey's default), so verification doesn't need any special audience config.
When ScaiKey isn't configured, the canvas falls back to a dev-token shared-secret bearer that only enables POST /v1/dev/deploy (deprecated legacy path).
Backend → ScaiGrid (token forwarding, with API-key fallback)#
When the user calls POST /v1/flows/{id}/deploy, the backend forwards their ScaiKey access token to ScaiGrid directly — ScaiGrid accepts the audience-client_id JWT natively.
For non-user contexts (the background ScaiKey sync loop, scheduled jobs, dev environments without an authenticated user), the backend falls back to a per-tenant API key stored in ScaiVault under tenants/{tenant_id}/scaigrid_api_key. Tenant admins set this via POST /v1/tenants/me/scaigrid_credentials.
You can pin the choice via SCAIFLOW_DEPLOY_AUTH=user_jwt|api_key for debugging.
ScaiKey → backend (webhooks)#
When users join/leave ScaiKey groups, ScaiKey fires signed webhooks at POST /v1/webhooks/scaikey. The backend verifies the HMAC-SHA256 signature against SCAIFLOW_SCAIKEY_WEBHOOK_SECRET, then updates its local user/group mirror.
The user/group mirror#
The backend maintains a local copy of every user and group in the tenant. This is what powers per-flow ACLs, super_admin role checks, and the tenant admin's "all users / all flows" views.
Sync runs on:
- Webhook delivery — incremental, near-real-time on join/leave events.
- Hourly fallback —
SCAIFLOW_SYNC_INTERVAL_MINUTES(default 60) runs a full sweep. - Manual trigger — super admins can hit
POST /v1/admin/sync. - CLI bootstrap —
scaiflow scaikey-registerprovisions the ScaiKey application + key, then triggers an initial sync.
The sync prefers applications.get_effective_users (platform-tier, returns every user with access regardless of group); falls back to a member-walk over groups.list_members for tenant-tier credentials that can't reach the platform API. The fallback is slower (O(N_groups × N_members) vs O(N_users)) but doesn't require platform-tier scope.
Permissions and roles#
ScaiFlow uses two canonical ScaiKey permissions:
scaicore:view— read-only access. Required for: listing flows, reading a flow, live preview, validation, browsing catalog, listing ScaiQueue scopes/queues/ScaiBunker bunkers, watching ScaiCore events.scaicore:manage— write access. Required for: create/update/delete flows, deploy, run tests, publish to catalog, resolve checkpoints, invoke a deployed Core.
There are no scaiflow:* permission variants — ScaiFlow piggy-backs on the ScaiCore permission pair so a single ScaiKey role config covers both.
Admin roles (ScaiFlow-local)#
Two roles maintained in ScaiFlow's DB (not ScaiKey):
tenant_admin— can see every flow in their tenant, manage tenant ScaiGrid credentials, granttenant_adminto others in their tenant.super_admin— platform-wide; can grant either role to anyone, sees all tenants.
Super_admin can be granted in three ways:
- Manual —
POST /v1/admin/users/{user_id}/rolewithrole=super_admin, source=manual. Survives reconciliation. - Group-derived — set
SCAIFLOW_SUPER_ADMIN_GROUPS=group_id_1,group_name_2. Members of any listed group are auto-elevated on sync (source=group). Removed from the group → auto-demoted. - First-user bootstrap — initial CLI sync; the first user with admin scopes can self-promote.
Per-flow ACLs#
Each flow has an ACL list:
[
{ "principal_type": "user", "principal_id": "usr_alice", "level": "edit" },
{ "principal_type": "group", "principal_id": "grp_devs", "level": "view" }
]
Levels are a strict hierarchy: view < edit < deploy < admin. Higher levels imply lower ones.
- Owner: implicit
admin— can't be removed. - Super admin: implicit
adminon every flow. - Tenant admin: implicit
adminon every flow in their tenant. - Catalog
publishaction: requiresdeployACL or higher.
Edit ACLs via POST /v1/flows/{id}/acls and DELETE /v1/flows/{id}/acls/{acl_id}.
Catalog visibility#
CatalogPackage.visibility is one of:
tenant— visible to anyone in the tenant.groups— restricted to specific group IDs (visibility_group_ids).
The author of a package implicitly sees it regardless of visibility. Super admins see all packages across all tenants.
Tenant ScaiGrid credentials#
A tenant admin can configure their ScaiGrid API key via:
1 2 3 4 5 6 7 | |
The key + base URL are written to ScaiVault at tenants/{tenant_id}/scaigrid_api_key and .../scaigrid_base_url. Background jobs and dev-token deploys read from there.
Status endpoint: GET /v1/tenants/me/scaigrid_credentials returns {configured, base_url, masked_key} (the key is masked as sgk_…last4).