Skip to main content

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

MethodEndpointDescription
GET/tenants/currentGet current tenant
GET/tenants/:idGet tenant by ID
PATCH/tenants/:idUpdate tenant
GET/tenants/:id/settingsGet tenant settings
PATCH/tenants/:id/settingsUpdate 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.