Data Isolation
Purpose and Scope
Data isolation ensures that resources belonging to one workspace cannot be accessed by users from another workspace. Every database record that represents user-created content is scoped to a workspace_id, and all API queries automatically filter by the authenticated user's workspace. This prevents workspace spoofing, unauthorized cross-workspace access, and data leaks between tenants.
For information about how workspaces are resolved and assigned to users, see Workspace Management. For details on the authentication flow that establishes the RequestContext, see Authentication Flow.
RequestContext as the Isolation Boundary
Every API endpoint receives a RequestContext from the get_request_context_hybrid authentication dependency. This context contains the resolved workspace_id and UserContext, which together define the isolation boundary for that request.
Sources: orchestrator/core/auth/hybrid.py:283-399, orchestrator/core/auth/dependencies.py
The RequestContext is constructed by get_request_context_hybrid after resolving the workspace through multiple strategies:
Explicit workspace ID from
x-workspace-idheader orworkspace_idquery parameterUser's workspace from Clerk organization or personal workspace
Auto-provisioned workspace for first-time Clerk users
Environment default from
WORKSPACE_IDorDEFAULT_WORKSPACE_ID
Once resolved, the workspace_id is immutable for the duration of the request and serves as the filter for all database operations.
Sources: orchestrator/core/auth/hybrid.py:29-68, orchestrator/core/auth/hybrid.py:190-254
Database Query Filtering Patterns
All workspace-scoped resources are filtered by workspace_id in their database queries. The pattern is consistent across all API routers.
Standard Query Pattern
Sources: orchestrator/api/agents.py:437-476, orchestrator/api/skills.py:418-501, orchestrator/api/patterns.py:15-41
Agent Queries Example
The agents API demonstrates the filtering pattern in all CRUD operations:
get_agent
.filter(Agent.id == agent_id, Agent.workspace_id == ctx.workspace_id)
update_agent
.filter(Agent.id == agent_id, Agent.workspace_id == ctx.workspace_id)
delete_agent
.filter(Agent.id == agent_id, Agent.workspace_id == ctx.workspace_id)
Sources: orchestrator/api/agents.py:437-741
Create Operations with Workspace Assignment
When creating new resources, the workspace_id is explicitly assigned from the RequestContext:
Sources: orchestrator/api/agents.py:359-428, orchestrator/api/patterns.py:44-86
Example from agent creation:
Sources: orchestrator/api/agents.py:374-383
Workspace Access Verification
The hybrid authentication system includes access verification to prevent workspace spoofing. When a client sends an explicit x-workspace-id header, the system verifies the authenticated user actually has access to that workspace.
Sources: orchestrator/core/auth/hybrid.py:71-82, orchestrator/core/auth/hybrid.py:84-107, orchestrator/core/auth/hybrid.py:283-350
Access Check Implementation
The _user_has_workspace_access function queries both workspace ownership and workspace membership:
A user has access to a workspace if:
They own the workspace (
workspaces.owner_id = users.id), ORThey are an active member (
workspace_members.is_active = true)
Sources: orchestrator/core/auth/hybrid.py:84-107
Spoofing Prevention
If a user attempts to access a workspace they don't belong to by manipulating the x-workspace-id header, the system falls back to resolving their default workspace instead of blocking the request entirely. This prevents breaking the UI while maintaining security:
Sources: orchestrator/core/auth/hybrid.py:316-323
Workspace-Scoped Database Models
The following database models include a workspace_id foreign key and are filtered by workspace in all queries:
Agent
agents
workspace_id
/api/agents
Skill
skills
(not workspace-scoped)
/api/v1/skills
Pattern
patterns
workspace_id
/api/patterns
Workflow
workflows
workspace_id
/api/workflows
WorkflowRecipe
workflow_recipes
workspace_id
/api/workflow-recipes
MarketplacePlugin
marketplace_plugins
owner_type + owner_id
/api/marketplace
WorkspaceEnabledPlugin
workspace_enabled_plugins
workspace_id
/api/workspaces/{id}/plugins
AgentAssignedPlugin
agent_assigned_plugins
(via agent)
/api/agents/{id}/plugins
Note: Skills are currently global resources shared across all workspaces, as they are loaded from Git repositories. Workspace-specific skill customization is planned for future releases.
Sources: orchestrator/core/models/agents.py, orchestrator/core/models/workflows.py, orchestrator/core/models/marketplace_plugins.py
Frontend Workspace Context
The frontend maintains workspace context through the WorkspaceProvider React context, which fetches the current workspace from /api/workspaces/current and provides it to all child components.
Sources: frontend/components/providers.tsx:1-86, frontend/components/workspace-provider.tsx, orchestrator/api/workspaces.py:24-54
Workspace API Response
The /api/workspaces/current endpoint returns the authenticated user's workspace, including a flag for first-time users:
The is_new_workspace flag is true when the workspace has no agents yet, triggering the onboarding flow via FirstLoginGuard.
Sources: orchestrator/api/workspaces.py:24-54, frontend/components/onboarding/first-login-guard.tsx:1-35
API Client Workspace Headers
The frontend API client automatically includes the workspace ID in request headers:
Sources: frontend/lib/api-client.ts
Isolation Boundaries and Guarantees
What Is Isolated
The following resources are strictly isolated by workspace:
Agents: Each workspace has its own set of agents with unique configurations
Workflows and Recipes: Workflow definitions and execution history are workspace-scoped
Patterns: Custom patterns are private to each workspace
Plugin Enablement: Workspaces must explicitly enable marketplace plugins before assignment
Tool Connections: Composio app connections are workspace-specific
Execution History: Workflow execution records are isolated per workspace
What Is Not Isolated
The following resources are shared across workspaces:
Skills: Loaded from Git repositories, skills are global and read-only
Marketplace Plugins: The marketplace catalog is visible to all users
Marketplace Agents: Shared agent templates are visible to all workspaces
LLM Models: Model configurations are system-wide
Composio App Definitions: The catalog of available apps is global
Sources: orchestrator/api/agents.py, orchestrator/api/skills.py, orchestrator/api/marketplace.py
Testing Data Isolation
To verify data isolation works correctly, follow this testing procedure:
1. Create Two Test Workspaces
Sources: orchestrator/core/auth/hybrid.py:110-187
2. Create Resources in Workspace A
Sources: orchestrator/api/agents.py:359-428
3. Attempt Cross-Workspace Access
Sources: orchestrator/api/agents.py:534-552
4. Attempt Header Spoofing
Sources: orchestrator/core/auth/hybrid.py:316-323
5. Verify Workspace Member Access
Sources: orchestrator/core/auth/hybrid.py:84-107
Common Isolation Patterns
Pattern 1: List Resources
Sources: orchestrator/api/agents.py:437-476, orchestrator/api/patterns.py:15-41
Pattern 2: Get Single Resource
Sources: orchestrator/api/agents.py:534-552, orchestrator/api/patterns.py:88-117
Pattern 3: Create Resource
Sources: orchestrator/api/agents.py:359-428, orchestrator/api/patterns.py:43-86
Pattern 4: Update Resource
Sources: orchestrator/api/agents.py:605-695
Pattern 5: Delete Resource
Sources: orchestrator/api/agents.py:697-740, orchestrator/api/patterns.py:119-141
Isolation in Statistics and Aggregations
Statistics endpoints must also filter by workspace to prevent information leakage:
Sources: orchestrator/api/agents.py:266-294
Even aggregate queries that don't return specific records must be scoped to prevent counting resources from other workspaces.
Summary
Data isolation in Automatos AI is enforced through:
Authentication Layer:
get_request_context_hybridresolves and validates workspace accessRequest Context: Every endpoint receives a
RequestContextwith immutableworkspace_idQuery Filtering: All database queries include
WHERE workspace_id = ?filtersAccess Verification: Workspace membership is verified to prevent header spoofing
Model Design: All user-created resources have a
workspace_idforeign keyFrontend Integration: React context and API client automatically include workspace headers
This multi-layered approach ensures complete data isolation between workspaces while maintaining a simple, consistent API pattern across all endpoints.
Sources: orchestrator/core/auth/hybrid.py:283-399, orchestrator/api/agents.py, orchestrator/api/patterns.py, frontend/components/workspace-provider.tsx
Last updated

