The MCP Gateway implements a comprehensive multi-tenant architecture that provides secure isolation, flexible resource sharing, and granular access control. This document describes the complete multi-tenancy design, user lifecycle, team management, and resource scoping mechanisms.
Installs into .claude/skills of the current project.
Are you the author of 078 Multitenancy Dafdda0c?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/tools-only-078-multitenancy-dafdda0c)
# Multi-Tenancy Architecture
The MCP Gateway implements a comprehensive multi-tenant architecture that provides secure isolation, flexible resource sharing, and granular access control. This document describes the complete multi-tenancy design, user lifecycle, team management, and resource scoping mechanisms.
## Overview
The multi-tenancy system is built around **teams as the primary organizational unit**, with users belonging to one or more teams, and all resources scoped to teams with configurable visibility levels.
### Core Principles
1. **Team-Centric**: Teams are the fundamental organizational unit for resource ownership and access control
2. **User Flexibility**: Users can belong to multiple teams with different roles in each team
3. **Resource Isolation**: Resources are scoped to teams with explicit sharing controls
4. **Invitation-Based**: Team membership is controlled through invitation workflows
5. **Role-Based Access**: Users have roles (Owner, Member) within teams that determine their capabilities
6. **Platform Administration**: Separate platform-level administration for system management
---
## User Lifecycle & Authentication
### User Authentication Flow
```mermaid
sequenceDiagram
participant U as User
participant G as Gateway
participant SSO as SSO Provider
participant DB as Database
participant E as Email Service
alt Email Authentication
U->>G: POST /auth/email/login
G->>DB: Validate email/password
DB-->>G: User record
G-->>U: JWT token + session
else SSO Authentication
U->>G: GET /auth/sso/login/github
G->>SSO: OAuth redirect
U->>SSO: Authorize application
SSO->>G: OAuth callback with code
G->>SSO: Exchange code for token
SSO-->>G: User profile data
G->>DB: Create/update user
G->>DB: Create personal team
G-->>U: JWT token + session
end
Note over G,DB: Personal team auto-created for new users
```
### User Creation & Personal Teams
When personal teams are enabled (default), each user gets an automatically created **Personal Team** upon registration:
```mermaid
flowchart TD
A[New User Registration] --> B{Authentication Method}
B -->|Email| C[Email Registration]
B -->|SSO| D[SSO Registration]
C --> E[Create EmailUser Record]
D --> F[Create SSO User Record]
E --> G[Create Personal Team<br/>if enabled]
F --> G
G --> H[Set User as Team Owner]
H --> I[User Can Access System]
subgraph "Personal Team Properties"
J[Name: Display Name's Team<br/>full name or email prefix]
K[is_personal: true]
L[Owner: User]
M[Members: User only]
N[Visibility: private]
end
G --> J
G --> K
G --> L
G --> M
G --> N
style G fill:#e1f5fe
style J fill:#f3e5f5
style K fill:#f3e5f5
style L fill:#f3e5f5
style M fill:#f3e5f5
style N fill:#f3e5f5
```
---
## Team Architecture & Management
### Team Structure & Roles
```mermaid
erDiagram
EmailTeam ||--o{ EmailTeamMember : has
EmailUser ||--o{ EmailTeamMember : belongs_to
EmailTeam ||--o{ EmailTeamInvitation : has_pending
EmailUser ||--o{ EmailTeamInvitation : invited_by
EmailTeam ||--o{ EmailTeamJoinRequest : join_requests
EmailUser ||--o{ EmailTeamJoinRequest : requested_by
EmailTeam {
string id PK
string name
string slug
string description
string created_by FK
boolean is_personal
string visibility
int max_members
boolean is_active
timestamp created_at
timestamp updated_at
}
EmailUser {
string email PK
string full_name
boolean is_admin
boolean is_active
string auth_provider
timestamp created_at
timestamp updated_at
}
EmailTeamMember {
string id PK
string team_id FK
string user_email FK
string role
string invited_by FK
timestamp joined_at
boolean is_active
}
EmailTeamInvitation {
string id PK
string team_id FK
string email
string role
string invited_by FK
timestamp invited_at
timestamp expires_at
string token
boolean is_active
}
EmailTeamJoinRequest {
string id PK
string team_id FK
string user_email FK
string status
timestamp requested_at
timestamp expires_at
timestamp reviewed_at
string reviewed_by FK
}
```
### Team Visibility & Access Model
```mermaid
flowchart TB
subgraph "Team Visibility Types"
T1["Private Team
Not discoverable; invite-only"]
T2["Public Team
Discoverable; membership by invite/request"]
end
subgraph "Team Roles"
R1["Owner
- Full team control
- Invite/remove members
- Manage resources
- Delete team"]
R2["Member
- Access team resources
- Create resources
- No member management"]
end
subgraph "Team Membership Flow"
A[User Exists] --> B{Team Type}
B -->|Private| C[Requires Invitation]
B -->|Public| D[Discover and Request Join]
C --> E[Owner Sends Invite]
E --> F[Pending Invitation]
F --> G[User Accepts/Declines]
D --> J[Join Request Pending]
J --> K[Owner Approves]
K --> H[User Joins Team]
G -->|Accept| H
H --> I[Team Member]
end
style T1 fill:#ffebee
style T2 fill:#e8f5e8
style R1 fill:#fff3e0
style R2 fill:#f3e5f5
```
#### Team Membership Levels (Design)
**Note**: These are team membership levels, separate from RBAC roles. A user can have both a membership level and RBAC role assignments within the same team.
- **Owner** (Team Membership Level):
- Manage team settings (name, description, visibility) and lifecycle (cannot delete personal teams).
- Manage membership (invite, accept, change roles, remove members).
- Full control over team resources (create/update/delete), subject to platform policies.
- **Member** (Team Membership Level):
- Access and use team resources; can create resources by default unless policies restrict it.
- Cannot manage team membership or team‑level settings.
**Platform Admin** is a global RBAC role (not a team membership level) with system‑wide oversight.
### Team Invitation Workflow
```mermaid
sequenceDiagram
participant O as Team Owner
participant G as Gateway
participant DB as Database
participant I as Invited User
Note over O,I: Invitation Process
O->>G: POST /teams/{team_id}/invitations
Note right of O: {email, role, expires_in}
G->>DB: Check team ownership
DB-->>G: Owner confirmed
G->>DB: Create invitation record
DB-->>G: Invitation token generated
G-->>O: Invitation created (token)
O-->>I: Share invite link (out of band)
Note over I,G: Acceptance Process
I->>G: POST /teams/invitations/{token}/accept
G->>DB: Validate token + user
G->>DB: Create team membership
G->>DB: Deactivate invitation (is_active=false)
G-->>I: Welcome to team
```
---
## Visibility Semantics
This section clarifies what Private and Public mean for teams, and what Private/Team/Public mean for resources across the system.
### Team Visibility (Design)
- Private:
- Discoverability: Not listed to non‑members; only visible to members/owner.
- Membership: By invitation from a team owner (request‑to‑join is not exposed to non‑members).
- API/UI: Team shows up only in the current user's teams list; direct deep links require membership.
- Public:
- Discoverability: Listed in public team discovery views for all authenticated users.
- Membership: Still requires an invitation or explicit approval of a join request.
- API/UI: Limited metadata may be visible without membership; all management and resource operations still require membership.
Note: Platform Admin is a global role and is not a team role. Admins can view/manage teams for operational purposes irrespective of team visibility.
### Resource Visibility (Design)
Applies to Tools, Servers, Resources, Prompts, and A2A Agents. All resources are owned by a team (team_id) and created by a user (owner_email).
- Private:
- Who sees it: Only the resource owner (owner_email).
- Team members cannot see or use it unless they are the owner.
- Mutations: Owner and Platform Admin can update/delete; team owners may be allowed by policy (see Enhancements).
- Team:
- Who sees it: All members of the owning team (owners and members).
- Mutations: Owner can update/delete; team owners can administratively manage; Platform Admin can override.
- Public:
- Who sees it: All authenticated users across the platform (cross‑team visibility).
- Mutations: Only the resource owner, team owners, or Platform Admins can modify/delete.
Enforcement summary:
- Listing queries include resources where (a) owner_email == user.email, (b) team_id ∈ user_teams with visibility ∈ {team, public}, and (c) visibility == public.
- Read follows the same rules as list; write operations require ownership or delegated/team administrative rights.
---
## Token Scoping Model
### How Token Scoping Works
Token scoping is the mechanism that determines which resources a user can **see** based on the `teams` claim in their JWT token. The `normalize_token_teams()` function in `mcpgateway/auth.py` is the **single source of truth** for interpreting JWT team claims.
### Secure-First Defaults
The token scoping system follows a **secure-first design principle**: when in doubt, access is restricted.
| JWT `teams` State | `is_admin` | Result | Access Level |
|-------------------|------------|--------|--------------|
| Key MISSING | any | `[]` | PUBLIC-ONLY (secure default) |
| Key `null` | `true` | `None` | ADMIN BYPASS (unrestricted) |
| Key `null` | `false` | `[]` | PUBLIC-ONLY (no bypass) |
| Key `[]` (empty) | any | `[]` | PUBLIC-ONLY |
| Key `["t1", "t2"]` | any | `["t1", "t2"]` | TEAM-SCOPED |
!!! warning "Critical Security Behavior"
A **missing** `teams` key always results in public-only access, even for admin users. Admin bypass requires **explicit** `teams: null` combined with `is_admin: true`.
### Multi-Team Token Behavior
When a token contains multiple teams (`teams: ["team-1", "team-2"]`):
- **Listing queries**: Return resources visible to ANY of the user's teams
- **`request.state.team_id`**: Set to the **first** team in the list
- **Resource creation**: Uses `request.state.team_id` as default if not explicitly specified
This means the first team in the token's teams array has special significance for default resource ownership.
### Return Value Semantics
The `normalize_token_teams()` function returns:
| Return Value | Meaning | Query Behavior |
|--------------|---------|----------------|
| `None` | Admin bypass | Skip ALL team filtering |
| `[]` (empty list) | Public-only | Filter to `visibility='public'` ONLY |
| `["t1", "t2"]` | Team-scoped | Filter to team resources + public |
---
## Two-Layer Security Model
MCP Gateway implements two distinct security layers that work together:
### Layer 1: Token Scoping (Data Filtering)
**Purpose**: Controls what resources a user CAN SEE
- Enforced by `TokenScopingMiddleware` and service layer queries
- Based on the `teams` claim in the JWT token
- Filters database queries based on visibility rules
- Applied **before** RBAC checks
### Layer 2: RBAC (Action Authorization)
**Purpose**: Controls what actions a user CAN DO
- Enforced by `@require_permission` decorators
- Based on role assignments and permission sets
- Checks if user has permission for the requested action
- Applied **after** token scoping passes
### Request Flow
```
Request: POST /tools/{id}/execute
│
▼
┌─────────────────────────────┐
│ Token Scoping (Layer 1) │ ← Can user ACCESS this tool?
│ - Check visibility │ (public/team/private)
│ - Check team membership │
└─────────────────────────────┘
│ (allowed)
▼
┌─────────────────────────────┐
│ RBAC Permission (Layer 2) │ ← Can user EXECUTE tools?
│ @require_permission( │ (tools.execute permission)
│ "tools.execute") │
└─────────────────────────────┘
│ (allowed)
▼
┌─────────────────────────────┐
│ Execute Operation │
└─────────────────────────────┘
```
### Enforcement Points Matrix
| Location | Token Scoping | RBAC | Notes |
|----------|--------------|------|-------|
| Token Scoping Middleware | ✅ | N/A | Request-level data filtering |
| REST API Endpoints | ✅ | ✅ | `@require_permission` decorators |
| RPC Handler (`/rpc`) | ✅ | Varies | Method-specific checks |
| Admin UI | ✅ | ✅ | Permission-based rendering |
| Service Layer | ✅ | N/A | Database query filtering |
| WebSocket | ✅ | ✅ | Forwards auth to /rpc |
| MCP Transport | ✅ | N/A | Streamable HTTP filtering |
---
## Resource Scoping & Visibility
### Resource Architecture
All resources in the MCP Gateway are scoped to teams with three visibility levels:
```mermaid
flowchart TD
subgraph "Resource Types"
A[MCP Servers]
B[Virtual Servers]
C[Tools]
D[Resources]
E[Prompts]
F[A2A Agents]
end
subgraph "Team Scoping"
G[team_id: UUID]
H[owner_email: string]
I[visibility: enum]
end
subgraph "Visibility Levels"
J["Private
Owner only"]
K["Team
Team members"]
L["Public
All users"]
end
A --> G
B --> G
C --> G
D --> G
E --> G
F --> G
G --> I
H --> I
I --> J
I --> K
I --> L
style J fill:#ffebee
style K fill:#e3f2fd
style L fill:#e8f5e8
```
### Resource Visibility Matrix
```mermaid
flowchart LR
subgraph "User Access to Resources"
U1["User A
Team 1 Member
Team 2 Owner"]
U2["User B
Team 1 Owner
Team 3 Member"]
U3["User C
No team membership"]
end
subgraph "Resource Visibility"
R1["Resource 1
Team 1, Private
Owner: User B"]
R2["Resource 2
Team 1, Team
Owner: User A"]
R3["Resource 3
Team 2, Public
Owner: User A"]
R4["Resource 4
Team 3, Team
Owner: User B"]
end
U1 -.->|❌ No Access| R1
U1 -->|✅ Team Member| R2
U1 -->|✅ Owner & Public| R3
U1 -.->|❌ Not Team Member| R4
U2 -->|✅ Owner & Private| R1
U2 -->|✅ Team Member| R2
U2 -->|✅ Public| R3
U2 -->|✅ Team Member| R4
U3 -.->|❌ No Access| R1
U3 -.->|❌ No Access| R2
U3 -->|✅ Public| R3
U3 -.->|❌ No Access| R4
style U1 fill:#e1f5fe
style U2 fill:#f3e5f5
style U3 fill:#fff3e0
```
### Resource Access Control Logic
```mermaid
flowchart TD
A[User requests resource access] --> B{Resource visibility}
B -->|Private| C{User owns resource?}
B -->|Team| D{User in resource team?}
B -->|Public| E[✅ Allow access]
C -->|Yes| F[✅ Allow access]
C -->|No| G[❌ Deny access]
D -->|Yes| H[✅ Allow access]
D -->|No| I[❌ Deny access]
style F fill:#e8f5e8
style H fill:#e8f5e8
style E fill:#e8f5e8
style G fill:#ffebee
style I fill:#ffebee
```
---
## Platform Administration
## Role-Based Access Control (RBAC)
The MCP Gateway implements a comprehensive RBAC system with four built-in roles that are automatically created during system bootstrap. These roles provide granular permission management across different scopes.
### System Roles
The following roles are created automatically when the system starts:
#### 1. Platform Admin (Global Scope)
- **Permissions**: `*` (all permissions)
- **Scope**: Global
- **Description**: Platform administrator with all system-wide permissions
- **Use Case**: System administrators who manage the entire platform
#### 2. Team Admin (Team Scope)
- **Permissions**:
- `teams.read` - View team information
- `teams.update` - Modify team settings
- `teams.join` - Join public teams
- `teams.manage_members` - Add/remove team members
- `tools.read` - View tools
- `tools.execute` - Execute tools
- `resources.read` - View resources
- `prompts.read` - View prompts
- **Scope**: Team
- **Description**: Team administrator with team management permissions
- **Use Case**: Team leaders who manage team membership and resources
#### 3. Developer (Team Scope)
- **Permissions**:
- `teams.join` - Join public teams
- `tools.read` - View tools
- `tools.execute` - Execute tools
- `resources.read` - View resources
- `prompts.read` - View prompts
- **Scope**: Team
- **Description**: Developer with tool and resource access
- **Use Case**: Team members who need to use tools and access resources
#### 4. Viewer (Team Scope)
- **Permissions**:
- `teams.join` - Join public teams
- `tools.read` - View tools
- `resources.read` - View resources
- `prompts.read` - View prompts
- **Scope**: Team
- **Description**: Read-only access to resources
- **Use Case**: Team members who only need to view resources without executing them
### Permission Categories
The RBAC system defines permissions across multiple resource categories:
#### User Management
- `users.create`, `users.read`, `users.update`, `users.delete`, `users.invite`
#### Team Management
- `teams.create`, `teams.read`, `teams.update`, `teams.delete`, `teams.manage_members`
#### Tool Management
- `tools.create`, `tools.read`, `tools.update`, `tools.delete`, `tools.execute`
#### Resource Management
- `resources.create`, `resources.read`, `resources.update`, `resources.delete`, `resources.share`
#### Prompt Management
- `prompts.create`, `prompts.read`, `prompts.update`, `prompts.delete`, `prompts.execute`
#### Server Management
- `servers.create`, `servers.read`, `servers.update`, `servers.delete`, `servers.manage`
#### Token Management
- `tokens.create`, `tokens.read`, `tokens.update`, `tokens.revoke`
#### Admin Functions
- `admin.system_config`, `admin.user_management`, `admin.security_audit`
### Role Assignment and Scope
Roles are assigned to users within specific scopes:
- **Global Scope**: Platform-wide permissions (platform_admin only)
- **Team Scope**: Team-specific permissions (team_admin, developer, viewer)
- **Personal Scope**: Individual user permissions (future use)
### Administrator Hierarchy
```mermaid
flowchart TD
subgraph "RBAC Roles"
A["Platform Admin
- All permissions (*)
- Global scope
- System management"]
B["Team Admin
- Team management
- Member control
- Resource access"]
C["Developer
- Tool execution
- Resource access
- No team management"]
D["Viewer
- Read-only access
- No execution
- No management"]
end
subgraph "Domain Restrictions"
E["Admin Domain Whitelist
SSO_AUTO_ADMIN_DOMAINS"]
F["Trusted Domains
SSO_TRUSTED_DOMAINS"]
G["Admin Approval Gate
SSO_REQUIRE_ADMIN_APPROVAL"]
end
A --> E
A --> G
B --> F
subgraph "Access Hierarchy"
H[Platform Admin] --> I[All Teams & Resources]
J[Team Admin] --> K[Team Resources & Members]
L[Developer] --> M[Team Resources Only]
N[Viewer] --> O[Read-Only Access]
end
style A fill:#ff8a80
style B fill:#ffb74d
style C fill:#81c784
style D fill:#90caf9
```
### Administrator Assignment Flow
```mermaid
sequenceDiagram
participant U as New User
participant G as Gateway
participant SSO as SSO Provider
participant DB as Database
participant A as Platform Admin
Note over U,A: SSO Registration with Domain + Approval Checks
U->>G: SSO Login (user@company.com)
G->>SSO: OAuth flow
SSO-->>G: User profile
G->>G: Check trusted domains (if configured)
alt Domain not trusted
G-->>U: Access denied
else Domain trusted
G->>G: Require admin approval?
alt Approval required (SSO_REQUIRE_ADMIN_APPROVAL=true)
G->>DB: Create PendingUserApproval
G-->>A: Approval required
A->>G: Approve user (admin UI)
Note over U,G: User logs in again after approval
U->>G: SSO Login (retry)
else Approval not required
Note right of G: Continue auto-create flow
end
G->>G: Evaluate admin criteria
Note right of G: Auto-admin domains / provider admin groups
G->>DB: Create user (is_admin true/false)
G-->>U: JWT token issued
end
```
## Password Management
MCP Gateway now supports:
- Self-service forgot-password/reset flow:
- `POST /auth/email/forgot-password`
- `GET /auth/email/reset-password/{token}`
- `POST /auth/email/reset-password/{token}`
- Admin unlock flow:
- `POST /auth/email/admin/users/{email}/unlock`
- Admin password reset via UI and API (`PUT /auth/email/admin/users/{email}`)
Operational guidance, Kubernetes recovery commands, emergency SQL procedures, and
SMTP/reset configuration are documented in:
- [Management: Password Management & Recovery](../manage/password-management.md)
### Password Security Requirements
- Argon2id hashing for stored credentials
- One-time reset tokens (hashed in DB, configurable expiry)
- Password reset request rate limiting
- Failed login tracking and account lockout controls
- Audit events for login/reset/lockout/unlock actions
### Role-Based UI Experience
The user interface adapts based on the user's assigned roles:
#### Platform Admin Experience
- **Full System Access**: Can view and manage all teams, users, and resources across the platform
- **Global Configuration**: Access to system-wide settings, SSO configuration, and platform management
- **Cross-Team Management**: Can manage resources in any team regardless of membership
- **User Management**: Can create, modify, and delete user accounts and role assignments
#### Team Admin Experience
- **Team Management**: Can modify team settings, manage team membership (invite/remove members)
- **Resource Control**: Full access to create, modify, and delete team resources
- **Member Oversight**: Can view and manage all team members and their access
- **Limited to Assigned Teams**: Only sees teams where they have the team_admin role
#### Developer Experience
- **Tool Access**: Can view and execute tools within their teams
- **Resource Usage**: Can access and use team resources and prompts
- **No Management Rights**: Cannot manage team membership or team settings
- **Create Resources**: Can create new tools, resources, and prompts within their teams
#### Viewer Experience
- **Read-Only Access**: Can view tools, resources, and prompts but cannot execute or modify them
- **No Creation Rights**: Cannot create new resources or tools
- **No Management Access**: Cannot manage team membership or settings
- **Limited Interaction**: Primarily for reviewing and consuming existing resources
### Default Visibility & Sharing
- Default on create: New resources (including MCP Servers, Tools, Resources, Prompts, and A2A Agents) default to `visibility="private"` unless a different value is explicitly provided by an allowed actor. For servers created via the UI, the visibility is enforced to `private` by default.
- Team assignment: When a user creates a server and does not specify `team_id`, the server is automatically assigned to the user's personal team.
- Sharing workflow:
- Private → Team: Make the resource visible to the owning team by setting `visibility="team"`.
- Private/Team → Public: Make the resource visible to all authenticated users by setting `visibility="public"`.
- Cross-team: To have a resource under a different team, create it in that team or move/clone it per policy; cross-team "share" is by visibility, not multi-team ownership.
---
## Complete Multi-Tenancy Flow
### End-to-End Resource Access
```mermaid
sequenceDiagram
participant U as User
participant G as Gateway
participant Auth as Authentication
participant Team as Team Service
participant Res as Resource Service
participant DB as Database
Note over U,DB: Complete Access Flow
U->>G: Request resource list
G->>Auth: Validate JWT token
Auth-->>G: User identity confirmed
G->>Team: Get user teams
Team->>DB: Query team memberships
DB-->>Team: User team list
Team-->>G: Teams with roles
G->>Res: List resources for user
Res->>DB: Query with team filtering
Note right of Res: WHERE owner_email = user OR team_id IN user_teams AND visibility IN team,public OR visibility = public
DB-->>Res: Filtered resource list
Res-->>G: User-accessible resources
G-->>U: Resource list response
Note over U,DB: Resource Creation
U->>G: Create new resource
G->>Auth: Validate permissions
G->>Team: Verify team membership
Team-->>G: Team access confirmed
G->>Res: Create resource
Res->>DB: INSERT with team_id, owner_email, visibility
DB-->>Res: Resource created
Res-->>G: Creation confirmed
G-->>U: Resource created successfully
```
### Team-Based Resource Filtering
```mermaid
flowchart TD
A[User Request] --> B[Extract User Identity]
B --> C[Get User Team Memberships]
C --> D[Build Filter Criteria]
D --> E{Resource Query}
E --> F["Owner-Owned Resources
owner_email = user.email"]
E --> G["Team Resources
team_id IN user.teams
AND visibility IN team,public"]
E --> H["Public Resources
visibility = public"]
F --> I[Combine Results]
G --> I
H --> I
I --> J[Apply Additional Filters]
J --> K[Return Filtered Resources]
subgraph "Filter Logic"
L[Personal: User owns directly]
M[Team: User is team member]
N[Public: Available to all]
end
style F fill:#e1f5fe
style G fill:#e3f2fd
style H fill:#e8f5e8
```
---
## Database Schema Design
### Core Multi-Tenant Schema (Key Fields)
```mermaid
erDiagram
%% User Management
EmailUser ||--o{ EmailTeamMember : belongs_to
EmailUser ||--o{ EmailTeamInvitation : invites
EmailUser ||--o{ EmailTeamJoinRequest : requests
EmailUser ||--o{ EmailTeam : creates
%% Team Management
EmailTeam ||--o{ EmailTeamMember : has
EmailTeam ||--o{ EmailTeamInvitation : has_pending
EmailTeam ||--o{ EmailTeamJoinRequest : has_requests
EmailTeam ||--o{ Tool : owns
EmailTeam ||--o{ Server : owns
EmailTeam ||--o{ Resource : owns
EmailTeam ||--o{ Prompt : owns
EmailTeam ||--o{ A2AAgent : owns
EmailUser {
string email PK
string full_name
boolean is_admin
boolean is_active
string auth_provider
timestamp created_at
timestamp updated_at
}
EmailTeam {
string id PK
string name
string slug
text description
string created_by FK
boolean is_personal
string visibility
int max_members
boolean is_active
timestamp created_at
timestamp updated_at
}
EmailTeamMember {
string id PK
string team_id FK
string user_email FK
string role
string invited_by FK
timestamp joined_at
boolean is_active
}
EmailTeamInvitation {
string id PK
string team_id FK
string email
string role
string invited_by FK
timestamp invited_at
string token
timestamp expires_at
boolean is_active
}
EmailTeamJoinRequest {
string id PK
string team_id FK
string user_email FK
string status
timestamp requested_at
timestamp expires_at
timestamp reviewed_at
string reviewed_by FK
string notes
}
Tool {
string id PK
string original_name
string display_name
string team_id FK
string owner_email
string visibility
timestamp created_at
timestamp updated_at
}
Resource {
string id PK
string uri
string name
string team_id FK
string owner_email
string visibility
timestamp created_at
timestamp updated_at
}
Prompt {
string id PK
string name
string original_name
string team_id FK
string owner_email
string visibility
timestamp created_at
timestamp updated_at
}
A2AAgent {
string id PK
string name
string slug
string team_id FK
string owner_email
string visibility
timestamp created_at
timestamp updated_at
}
Server {
string id PK
string name
string team_id FK
string owner_email
string visibility
timestamp created_at
timestamp updated_at
}
```
---
## API Design Patterns
### Team-Scoped Endpoints
All resource endpoints follow consistent team-scoping patterns:
```mermaid
flowchart TD
subgraph "API Endpoint Patterns"
A["GET /tools?team_id=uuid&visibility=team"]
B["POST /tools
name, team_id (optional), visibility"]
C["GET /tools/{tool_id}"]
D["PUT /tools/{tool_id}
visibility, name, etc."]
E["DELETE /tools/{tool_id}"]
end
subgraph "Request Processing"
F[Extract User Identity] --> G[Validate Team Access]
G --> H[Apply Team Filters]
H --> I[Execute Query]
I --> J[Return Results]
end
subgraph "Access Control Checks"
K[User Team Membership]
L[Resource Ownership]
M[Visibility Level]
N[Operation Permissions]
end
A --> F
B --> F
C --> F
D --> F
E --> F
G --> K
G --> L
G --> M
G --> N
style A fill:#e1f5fe
style B fill:#f3e5f5
style C fill:#fff3e0
style D fill:#e8f5e8
style E fill:#ffebee
```
### Resource Creation Flow
```mermaid
sequenceDiagram
participant C as Client
participant G as Gateway
participant A as Auth Middleware
participant R as Resource Service
participant DB as Database
C->>G: POST /tools
Note right of C: {name, team_id, visibility}
G->>A: Validate request
A->>A: Extract user from JWT
A->>A: Enforce permissions + token scope
A-->>G: User authorized
G->>R: Create resource
R->>R: Validate payload + defaults
R->>DB: INSERT resource
Note right of R: team_id, owner_email, visibility
DB-->>R: Resource created
R-->>G: Creation response
G-->>C: 201 Created
```
---
## Configuration & Environment
### Multi-Tenancy Configuration
```bash
#####################################
# Multi-Tenancy Configuration
#####################################
# Team Settings
AUTO_CREATE_PERSONAL_TEAMS=true
PERSONAL_TEAM_PREFIX=personal
MAX_TEAMS_PER_USER=50
MAX_MEMBERS_PER_TEAM=100
# Team Invitation Settings
INVITATION_EXPIRY_DAYS=7
REQUIRE_EMAIL_VERIFICATION_FOR_INVITES=true
# Visibility
# NOTE: Resources default to 'private' (not configurable via env today)
# Allowed visibility values: private | team | public
# Platform Administration
PLATFORM_ADMIN_EMAIL=admin@company.com
PLATFORM_ADMIN_PASSWORD=changeme
PLATFORM_ADMIN_FULL_NAME="Platform Administrator"
# SSO (enable + trust and admin mapping)
SSO_ENABLED=true
SSO_TRUSTED_DOMAINS=["company.com","trusted-partner.com"]
SSO_AUTO_ADMIN_DOMAINS=["company.com"]
SSO_GITHUB_ADMIN_ORGS=["your-org"]
SSO_GOOGLE_ADMIN_DOMAINS=["your-google-workspace-domain.com"]
SSO_REQUIRE_ADMIN_APPROVAL=false
# Public team self-join flows are planned; no env toggles yet
```
---
## Security Considerations
### Multi-Tenant Security Model
```mermaid
flowchart TD
subgraph "Security Layers"
A["Authentication Layer
- JWT validation
- Session management"]
B["Authorization Layer
- Team membership
- Resource ownership
- Visibility checks"]
C["Data Isolation Layer
- Team-scoped queries
- Owner validation
- Access logging"]
end
subgraph "Security Controls"
D["Input Validation
- Team ID validation
- Email format
- Role validation"]
E["Rate Limiting
- Per-user limits
- Per-team limits
- API quotas"]
F["Audit Logging
- Access attempts
- Resource changes
- Team modifications"]
end
subgraph "Attack Prevention"
G["Team Enumeration
- UUID team IDs
- Access validation"]
H["Resource Access
- Ownership checks
- Visibility enforcement"]
I["Privilege Escalation
- Role validation
- Permission boundaries"]
end
A --> B --> C
D --> E --> F
G --> H --> I
style A fill:#ffcdd2
style B fill:#f8bbd9
style C fill:#e1bee7
style D fill:#c8e6c9
style E fill:#dcedc8
style F fill:#f0f4c3
```
### RBAC Access Control Matrix
| RBAC Role | Scope | Team Access | Resource Creation | Member Management | Team Settings | Platform Admin |
|-----------|-------|-------------|-------------------|-------------------|---------------|----------------|
| Platform Admin | Global | All teams | All resources | All teams | All settings | Full access |
| Team Admin | Team | Assigned teams | Team resources | Team members | Team settings | No access |
| Developer | Team | Member teams | Team resources | No access | No access | No access |
| Viewer | Team | Member teams | No access | No access | No access | No access |
**Note**: Team Owner/Member roles from the team management system work alongside RBAC roles. A user can have both team membership status (Owner/Member) and RBAC role assignments (Team Admin/Developer/Viewer) within the same team.
### Token Scoping Invariants
These behaviors are enforced consistently across all access paths:
1. `normalize_token_teams()` is the ONLY function that interprets JWT team claims
2. Missing `teams` key always returns `[]` (public-only, secure default)
3. Admin bypass requires BOTH `teams: null` AND `is_admin: true`
4. Empty teams list (`[]`) results in public-only access, even for admins
5. All list endpoints pass `token_teams` to the service layer
6. Service layer applies visibility filtering based on `token_teams`
7. Public-only tokens can ONLY access `visibility='public'` resources
### Related Documentation
For detailed information on RBAC configuration, token scoping, and permission management, see [RBAC Configuration](../manage/rbac.md).
---
## Implementation Verification
### Key Requirements Checklist
- [x] **User Authentication**: Email and SSO authentication implemented
- [x] **Personal Teams**: Auto-created for every user
- [x] **Team Roles**: Owner and Member roles (platform Admin is global)
- [x] **Team Visibility**: Private and Public team types
- [x] **Resource Scoping**: All resources scoped to teams with visibility controls
- [x] **Invitation System**: Email-based invitations with token management
- [x] **Platform Administration**: Separate admin role with domain restrictions
- [x] **Access Control**: Team-based filtering for all resources
- [x] **Database Design**: Complete multi-tenant schema
- [x] **API Patterns**: Consistent team-scoped endpoints
### Critical Implementation Points
1. **Team ID Validation**: Every resource operation must validate team membership
2. **Visibility Enforcement**: Resource visibility (private/team/public) strictly enforced; team visibility (private/public) per design
3. **Owner Permissions**: Only team owners can manage members and settings
4. **Personal Team Protection**: Personal teams cannot be deleted or transferred
5. **Invitation Security**: Invitation tokens with expiration and single-use
6. **Platform Admin Isolation**: Platform admin access separate from team access
7. **Cross-Team Access**: Public resources accessible across team boundaries
8. **Audit Trail**: Permission checks and auth events audited; extended operation audit planned
---
## Gaps & Issues
- Team roles: Owner and Member only (platform Admin is global) — consistent across ERD, APIs, and UI.
- Team visibility: Private and Public.
- Resource visibility: `private|team|public` — enforced as designed.
- Public team discovery/join: Join‑request/self‑join flows to be implemented.
- Default resource visibility: Defaults to "private"; not configurable via env.
- SSO admin mapping: Domain/org lists supported; provider‑specific org checks may require provider API calls in production.
---
## Enhancements & Roadmap (Part of the Design)
- Public Team Discovery & Join Requests:
- Add endpoints and UI to request membership on public teams; owner approval workflow; optional auto‑approve policy.
- Admin toggles/policies to restrict who can create public teams and who can approve joins.
- Unified Operation Audit:
- System‑wide audit log for create/update/delete across teams, tools, servers, resources, prompts, agents with export/reporting.
- Role Automation:
- Auto‑assign default RBAC roles on resource creation (e.g., owner gets manager role in team scope; members get viewer).
- Optional per‑team policies defining who may create public resources.
- ABAC for Virtual Servers:
- Attribute‑based conditions layered on top of RBAC (tenant tags, data classifications, environment, time windows, client IP).
- Team/Resource Quotas and Policies:
- Per‑team limits (tools/servers/resources/agents); per‑team defaults for resource visibility and creation rights.
- Public Resource Access Controls:
- Fine‑grained cross‑tenant rate limits and opt‑in masking for metadata shown to non‑members.
This architecture provides a robust, secure, and scalable multi-tenant system that supports complex organizational structures while maintaining strict data isolation and flexible resource sharing capabilities.