Flow Studio
Tenant Scoping
How identity queries are automatically scoped to the execution's tenant — preventing cross-tenant data leakage and ensuring workflows only resolve users within their own organization.
How Tenant Scoping Works
Every IPassportClient request includes a TenantId field. This is always set to ctx.TenantId by the executor — it is not configurable in node config and cannot be overridden by an expression. Passport rejects any query that resolves a user outside the specified tenant.
// Executors always pass ctx.TenantId:
var request = new UserLookupRequest
{
LookupBy = config.LookupBy,
Value = lookupValue,
TenantId = ctx.TenantId // from execution context — not from config
};
var user = await _passport.LookupUserAsync(request, ct);
What Tenant Scoping Prevents
| Scenario | Result |
|---|---|
| Tenant A workflow queries Tenant B user email | Passport returns null — user not found in tenant scope |
| Expression attempts to pass cross-tenant userId | Passport returns null or 404 — no error leakage |
| RoleMembers query for role in another tenant | Returns empty members list |
| PermissionCheck for cross-tenant user ID | Returns false — permission denied |
Sub-Workflow Tenant Inheritance
Sub-workflows always inherit the parent execution's tenantId. There is no mechanism to execute a child workflow in a different tenant. This applies to both sync and async sub-workflow modes.
No opt-out: Tenant scoping on identity queries is not configurable and cannot be disabled — not by node config, expressions, or executor code. Any attempt to resolve cross-tenant identity returns a negative result, not an error. This is a deliberate security design: cross-tenant queries fail silently to prevent tenant enumeration attacks.