Multi-Tenancy
CORTEX implements strict multi-tenancy where every piece of data belongs to exactly one tenant. Tenants are completely isolated from each other at the application and database level.
Tenant Model
A tenant represents a single customer or organization using the CORTEX platform. Each tenant has:
- A unique identifier (UUID)
- A unique slug (URL-friendly name)
- Independent configuration and settings
- Complete data isolation from other tenants
- Their own users, organizations, roles, and permissions
Isolation Model
┌─────────────────────────────────────────────────────┐
│ CORTEX Platform │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Tenant: Acme │ │ Tenant: GlobalTech│ │
│ │ │ │ │ │
│ │ Users: 50 │ │ Users: 200 │ │
│ │ Orgs: 3 │ │ Orgs: 8 │ │
│ │ Roles: 5 │ │ Roles: 12 │ │
│ │ │ │ │ │
│ │ 🔒 Isolated │ │ 🔒 Isolated │ │
│ └─────────────────┘ └─────────────────┘ │
│ ❌ No cross-tenant access ❌ │
└─────────────────────────────────────────────────────┘
Security: Why 404 Instead of 403?
When a user from Tenant A attempts to access a resource in Tenant B, CORTEX returns 404 Not Found instead of 403 Forbidden. This is a deliberate security decision:
- 403 reveals that the resource exists (information leakage)
- 404 reveals nothing about other tenants' data
This prevents tenant ID enumeration attacks where an attacker could discover which tenant IDs are valid.
Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /tenants/current | Get current tenant |
GET | /tenants/:id | Get tenant by ID |
PATCH | /tenants/:id | Update tenant |
GET | /tenants/:id/settings | Get tenant settings |
PATCH | /tenants/:id/settings | Update settings (merge) |
How Tenant Context Works
The tenant is determined from the authenticated user's JWT token. Every request includes the user's tenantId, which is used to scope all database queries.
// Simplified flow
@Get('users')
async getUsers(@CurrentUser() user: RequestUser) {
// Automatically scoped to user's tenant
return this.userService.findAll({
tenantId: user.tenantId,
});
}
Tenant Data Model
interface Tenant {
id: string; // UUID
name: string; // Display name
slug: string; // URL-friendly identifier
status: TenantStatus; // ACTIVE, SUSPENDED, INACTIVE
settings: object; // Tenant-specific configuration
createdAt: Date;
updatedAt: Date;
}
enum TenantStatus {
ACTIVE = 'ACTIVE',
SUSPENDED = 'SUSPENDED',
INACTIVE = 'INACTIVE',
}
Cross-Tenant Operations
Cross-tenant operations are only allowed for platform administrators (users with PLATFORM scope roles). These operations include:
- Creating new tenants
- Viewing all tenants
- Suspending tenants
- Managing cross-tenant data migrations
Regular users can only access data within their own tenant.