Authentication & Multi-Tenancy
Purpose & Scope
This document describes Automatos AI's authentication and multi-tenancy architecture. It covers Clerk JWT-based authentication, workspace-scoped data isolation, and secure credential management across the platform.
For workspace creation and management UI, see Workspace Management. For credential storage and resolution strategies, see Credentials Management. For API security and rate limiting, see Backend Architecture.
Authentication Architecture
Clerk JWT Integration
Automatos AI uses Clerk for authentication, providing secure JWT-based identity verification without requiring password management infrastructure. Authentication is optional during local development but required in production.
Configuration (config.py:168-175):
CLERK_SECRET_KEY: str = os.getenv("CLERK_SECRET_KEY")
CLERK_PUBLISHABLE_KEY: str = os.getenv("NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY")
CLERK_JWKS_URL: str = os.getenv("CLERK_JWKS_URL")
CLERK_AUDIENCE: str = os.getenv("CLERK_AUDIENCE", "")The system enforces authentication via REQUIRE_AUTH flag (config.py:87), which defaults to true in production but can be disabled for local development.
Sources: orchestrator/config.py:168-175, orchestrator/config.py:87
Authentication Flow
Authentication Steps:
Frontend Authentication: User authenticates through Clerk's UI components (
/sign-in,/sign-up)JWT Issuance: Clerk issues a JWT token to the authenticated user
Token Retrieval: Frontend calls
getToken()from Clerk's React SDKRequest Headers: Frontend includes
Authorization: Bearer {JWT}andX-Workspace-IDheadersJWT Verification: Backend validates JWT signature using Clerk's JWKS endpoint
Workspace Validation: Backend confirms user's membership in the specified workspace
Request Context: Successful validation creates a
RequestContextwithuser_idandworkspace_id
Sources: orchestrator/main.py:118-122, orchestrator/config.py:168-175, frontend/lib/api-client.ts:160-163
Request Context & Middleware
Middleware Pipeline
Every API request flows through a standardized middleware pipeline that enforces authentication, workspace isolation, and security policies.
Middleware Execution Order (main.py:555-642):
CORS Middleware (line 560): Validates origin against allowed list
Rate Limiting (line 583): Enforces 60 requests/minute per IP (configurable)
Body Size Limit (line 603): Prevents payload too large (10MB default, 50MB for uploads)
Security Headers (line 617): Adds CSP, X-Frame-Options, HSTS in production
Request ID (line 632): Assigns unique ID for distributed tracing
API Tracking (line 643): Records metrics to
api_call_statsdictAuthentication (implicit): Enforced by dependency injection in route handlers
Sources: orchestrator/main.py:555-688, orchestrator/main.py:583-596
Request Context Resolution
The get_request_context_hybrid dependency provides workspace-aware authentication to route handlers.
Workspace Resolution Priority (from highest to lowest):
X-Workspace-IDHeader: Explicitly specified workspace (validated against user membership)DEFAULT_WORKSPACE_IDEnvironment Variable: Fallback for requests without workspace headerDEFAULT_TENANT_IDConstant: UUID00000000-0000-0000-0000-000000000000for single-tenant mode
Sources: orchestrator/core/auth/hybrid.py:1-200, orchestrator/config.py:21-23, orchestrator/config.py:173-174
Multi-Tenancy Architecture
Five-Layer Data Isolation
Automatos AI implements workspace isolation across five infrastructure layers to ensure complete tenant separation.
Sources: Diagram 8 from high-level system diagrams
Database Isolation
All major tables include a workspace_id column with foreign key constraints to the workspaces table. Queries automatically filter by the authenticated user's workspace.
Example Table Structure (core/models/core.py:1-500):
Query Pattern (api/agents.py:50-200):
Marketplace vs Workspace Items:
The owner_type field distinguishes shared marketplace items from workspace-private items:
owner_type = "marketplace": Globally available (e.g., community plugins, personas)owner_type = "workspace": Private to the owning workspace
Sources: orchestrator/core/models/core.py:1-500, orchestrator/api/agents.py:1-300
S3 Storage Isolation
All S3 objects use workspace-prefixed keys to prevent cross-tenant access. Vector embeddings are stored in per-workspace buckets.
S3 Key Structure (config.py:246-260):
Documents
workspaces/{workspace_id}/documents/{doc_id}/
workspaces/abc123/documents/report.pdf
Vectors
Separate bucket per workspace
automatos-vectors-abc123
Recipe Logs
workspaces/{workspace_id}/logs/{execution_id}/
workspaces/abc123/logs/exec-456.json
Generated Images
workspaces/{workspace_id}/images/{image_id}
workspaces/abc123/images/chart.png
Configuration (config.py:252-260):
Sources: orchestrator/config.py:246-260, orchestrator/modules/rag/service.py:1-550
Redis Isolation
Redis keys use workspace-scoped prefixes to prevent cache leakage between tenants.
Key Naming Conventions (core/redis/client.py:1-200):
Redis Configuration with Security (docker-compose.yml:48-73):
The Redis instance is hardened by disabling dangerous commands (FLUSHDB, FLUSHALL, DEBUG) that could wipe data if exposed.
Sources: orchestrator/core/redis/client.py:66-119, docker-compose.yml:48-73
Filesystem Isolation
The workspace worker service isolates code execution in per-workspace directories with quota enforcement and path safety validation.
Volume Configuration (docker-compose.yml:174-217):
Path Safety Validation (workspace-worker service):
Security Policies:
Path Safety: Blocks
.., symlinks, absolute pathsCommand Whitelist: Only approved binaries can execute
Storage Quotas: Default 5GB per workspace (configurable)
Environment Sandbox: Stripped
PATH, no host variablesResource Limits: CPU and memory limits enforced by Docker
Sources: docker-compose.yml:174-217, orchestrator/config.py:219-226
Credential Management
Credential Types & Storage
Automatos AI supports multiple credential types with secure encrypted storage. Credentials are scoped to workspaces and encrypted at rest.
Credential Table Schema:
Encryption Configuration (config.py:175):
Sources: orchestrator/config.py:175, orchestrator/core/database/load_seed_data.py:62-103
Six-Level Credential Resolution
When agents request LLM credentials, the system follows a six-level fallback strategy to maximize availability while respecting workspace boundaries.
Resolution Strategy (implemented in LLMManager):
Agent-Specific Credential: Check
agent.model_config.credentialsWorkspace Default Credential: Query
credentialstable filtered byworkspace_idSystem Settings Credential: Check
system_settingstable (admin-configured defaults)User API Key (BYOK): Check
user_api_keystable for bring-your-own-keyEnvironment Variable: Fall back to
OPENAI_API_KEY,ANTHROPIC_API_KEY, etc.Fallback Provider: If primary provider fails, try secondary (e.g., GPT-4 → Claude)
Sources: orchestrator/core/llm/manager.py:200-650, orchestrator/modules/agents/factory/agent_factory.py:200-650
Composio OAuth Connections
External tool integrations via Composio use workspace-scoped OAuth connections stored in the entity_connections table.
Entity Connection Storage:
Connection Flow:
User clicks "Connect" on a Composio app in the marketplace
Frontend redirects to Composio OAuth consent page with
entity_id = workspace_{workspace_id}User grants permissions
Composio callback stores encrypted tokens in
entity_connectionsAgents can now use the connected app via
ComposioToolService
Permission Validation (modules/tools/execution/unified_executor.py:1-800):
Sources: orchestrator/modules/tools/services/composio_tool_service.py:1-360, orchestrator/modules/tools/execution/unified_executor.py:1-800
Frontend Integration
Clerk React SDK Setup
The frontend uses Clerk's React SDK to handle authentication UI and token management.
Provider Configuration (frontend/app/layout.tsx or similar):
Token Injection (frontend/lib/api-client.ts:157-163):
The ApiClient class accepts a token getter function from components with access to Clerk's useAuth() hook, then includes the JWT in all API requests.
Sources: frontend/lib/api-client.ts:157-163, orchestrator/config.py:168-171
Workspace Selection
The frontend maintains workspace context in localStorage and provides admin override capabilities for support scenarios.
Workspace Header Injection (frontend/lib/api-client.ts:803-816):
Admin Override Functions (frontend/lib/api-client.ts:83-91):
This allows admin users to temporarily impersonate workspaces for debugging without changing localStorage.
Sources: frontend/lib/api-client.ts:803-816, frontend/lib/api-client.ts:83-91
Security Considerations
Production Hardening
Security Headers (main.py:617-627):
Database SSL Enforcement (config.py:46-58):
Production database connections enforce SSL mode unless connecting to local development databases.
Sources: orchestrator/main.py:617-627, orchestrator/config.py:46-58
Rate Limiting
SlowAPI provides IP-based rate limiting with configurable limits per endpoint.
Configuration (main.py:583-596):
The rate limiter respects X-Forwarded-For headers when behind reverse proxies (e.g., Railway, Cloudflare) to correctly identify client IPs.
Sources: orchestrator/main.py:583-596
Request Body Size Limits
The backend enforces different body size limits based on endpoint type to prevent resource exhaustion.
Middleware (main.py:598-614):
Limits:
Default: 10MB for API requests
Uploads: 50MB for document/plugin uploads
Sources: orchestrator/main.py:598-614
Redis Security Hardening
The Redis instance is hardened by disabling dangerous administrative commands.
Disabled Commands (docker-compose.yml:54-62):
This prevents accidental or malicious data wipes if the Redis instance is exposed (e.g., misconfigured firewall). The CONFIG command is also renamed, breaking redis-cli CONFIG but preventing runtime configuration changes.
Sources: docker-compose.yml:54-62
Environment Configuration
Required Variables
Minimum Configuration (.env.example:1-65):
Sources: orchestrator/.env.example:1-65
Docker Compose Configuration
Backend Service (docker-compose.yml:78-138):
Frontend Service (docker-compose.yml:146-170):
The frontend only receives public-safe environment variables (NEXT_PUBLIC_* prefix). Secrets like CLERK_SECRET_KEY stay server-side only.
Sources: docker-compose.yml:78-170
Development Workflow
Local Development Setup
Copy Environment Template:
Configure Clerk (optional for local dev):
Create a Clerk application at https://clerk.com
Copy API keys to
.envSet
REQUIRE_AUTH=falseto bypass authentication locally
Start Services:
Access Application:
Frontend: http://localhost:3000
Backend: http://localhost:8000
API Docs: http://localhost:8000/docs
Development Mode Authentication:
When REQUIRE_AUTH=false, the system allows unauthenticated requests and assigns a default workspace ID. This simplifies local testing without requiring Clerk setup.
Sources: orchestrator/config.py:87-88, orchestrator/.env.example:33
Testing Multi-Tenancy
Manual Workspace Testing:
Create multiple workspaces via API or UI
Switch workspace context by changing
X-Workspace-IDheaderVerify data isolation:
Agents from workspace A should not appear in workspace B
Document uploads should use workspace-prefixed S3 keys
Redis cache keys should include workspace ID
Admin Override Testing (frontend/lib/api-client.ts:83-91):
Sources: frontend/lib/api-client.ts:83-91
Migration from Single-Tenant
Adding Workspace Support to Existing Tables
Migration Template:
Update Query Logic:
Sources: orchestrator/core/models/core.py:1-500
Summary
Authentication
Clerk JWT validation
CLERK_SECRET_KEY, CLERK_JWKS_URL
Database
workspace_id column + filters
Foreign key to workspaces table
S3 Storage
Path prefix workspaces/{id}/
Per-workspace vector buckets
Redis Cache
Key prefix workspace:ws:{id}:
Workspace-scoped keys
Filesystem
Volume path /workspaces/{id}/
WORKSPACE_VOLUME_PATH env var
Credentials
Encrypted per workspace
CREDENTIAL_ENCRYPTION_KEY
Rate Limiting
IP-based (60/min default)
SlowAPI middleware
Request Context
get_request_context_hybrid
X-Workspace-ID header
Automatos AI's multi-tenancy architecture ensures complete data isolation through layered security controls, allowing thousands of workspaces to operate securely on shared infrastructure.
Sources: orchestrator/main.py:1-800, orchestrator/config.py:1-423, frontend/lib/api-client.ts:1-1500
Last updated

