Skip to content

Component: Tenant APIs

Date: December 16, 2025
Status: Architecture Specification
Component Type: Backend API Services


Table of Contents

  1. Overview
  2. Architecture
  3. Tenant Management API
  4. User Management API
  5. CAT Management API
  6. Data Isolation
  7. API Endpoints
  8. Authentication & Authorization
  9. Error Handling
  10. Implementation Details
  11. Testing Strategy
  12. Deployment

Overview

The Tenant APIs are FastAPI-based backend services that handle tenant-specific operations, user management, CAT (Conversational AI Technology) management, and data isolation. These APIs enforce tenant boundaries at the database and application level.

Key Responsibilities

  • Tenant Management: CRUD operations for tenants
  • User Management: Tenant-scoped user operations
  • CAT Management: Tenant-scoped CAT operations
  • Data Isolation: Enforce tenant boundaries in data access
  • Configuration Management: Tenant-specific configurations
  • Access Control: Tenant-level authorization

API Services

  1. Security API (bast-security-api)
  2. Authentication
  3. Authorization
  4. JWT token management

  5. User Management API (bast-user-management-api)

  6. Tenant management
  7. User management (per tenant)
  8. CAT management (per tenant)
  9. Configuration management

  10. CAT API (bast-cat-api)

  11. CAT-specific operations
  12. Chat processing
  13. Conversation management

Architecture

High-Level Architecture

┌─────────────────────────────────────────────────────────┐
│              BFF Tenant Aware                            │
│  - Tenant ID in headers (X-Tenant-ID)                  │
└────────────────────┬────────────────────────────────────┘
                     │ HTTP Request
                     │ Headers: X-Tenant-ID, X-CAT-Prefix
                     ▼
┌─────────────────────────────────────────────────────────┐
│              Tenant APIs (FastAPI)                      │
│                                                          │
│  ┌──────────────────────────────────────────────────┐  │
│  │  Security API                                    │  │
│  │  - Authentication (tenant-aware)                │  │
│  │  - Authorization (tenant-scoped)                │  │
│  └──────────────────────────────────────────────────┘  │
│                        │                                │
│  ┌──────────────────────────────────────────────────┐  │
│  │  User Management API                              │  │
│  │  - Tenant CRUD                                   │  │
│  │  - User CRUD (per tenant)                        │  │
│  │  - CAT CRUD (per tenant)                         │  │
│  │  - Configuration (per tenant)                    │  │
│  └──────────────────────────────────────────────────┘  │
│                        │                                │
│  ┌──────────────────────────────────────────────────┐  │
│  │  CAT API                                         │  │
│  │  - Chat (per CAT)                                │  │
│  │  - Conversations (per CAT)                       │  │
│  │  - Configuration (per CAT)                        │  │
│  └──────────────────────────────────────────────────┘  │
└────────────────────┬────────────────────────────────────┘
                     │
         ┌───────────┴───────────┐
         │                       │
┌────────▼────────┐    ┌────────▼────────┐
│  MongoDB        │    │  Other DBs      │
│  - auth_db      │    │  - GraphDB       │
│  - config_db    │    │  - VectorDB      │
│  - {prefix}_*   │    │  - CloudStorage  │
└─────────────────┘    └──────────────────┘

Database Structure

auth_db (shared)
├── users (collection)
│   └── { user_id, email, organization, tenants: [] }
└── user_memories (collection)

config_db (shared)
├── tenants (collection)
│   └── { tenant_id, name, slug, status, config }
└── cat_config (collection)
    └── { prefix, tenant_id, name, config }

{tenant_id}_cat_data (tenant-specific)
├── logs (collection)
├── sessions (collection)
└── metrics (collection)

{prefix}_cat_data (CAT-specific)
├── logs (collection)
├── sessions (collection)
└── metrics (collection)

Tenant Management API

Endpoints

Get Tenant

GET /api/v1/tenants/{tenant_id}

Response:
{
  "tenant_id": "acme",
  "name": "Acme Corporation",
  "slug": "acme",
  "status": "active",
  "created_at": "2025-01-01T00:00:00Z",
  "updated_at": "2025-01-01T00:00:00Z",
  "subscription": {
    "tier": "standard",
    "expires_at": null
  }
}

Get Tenant Configuration

GET /api/v1/tenants/{tenant_id}/config

Response:
{
  "tenant_id": "acme",
  "branding": {
    "logo": "https://cdn.bast.ai/tenants/acme/logo.png",
    "logo_dark": "https://cdn.bast.ai/tenants/acme/logo-dark.png",
    "colors": {
      "primary": "#2295c4",
      "secondary": "#02736b",
      "accent": "#55ccd9"
    },
    "theme": "auto"
  },
  "features": {
    "enabled": ["ontology", "governance", "analytics"],
    "disabled": ["advanced_ai"],
    "limits": {
      "max_cats": 10,
      "max_users": 100,
      "max_storage": 1000
    }
  },
  "environments": ["dev", "stage", "prod"]
}

Update Tenant Configuration

PUT /api/v1/tenants/{tenant_id}/config
Headers: X-Tenant-ID: {tenant_id}, Authorization: Bearer {token}

Request Body:
{
  "branding": {
    "logo": "https://...",
    "colors": {
      "primary": "#2295c4"
    }
  }
}

Response:
{
  "success": true,
  "updated_at": "2025-01-01T00:00:00Z"
}

List Tenants (Admin Only)

GET /api/v1/tenants
Headers: Authorization: Bearer {admin_token}

Query Parameters:
- limit: int = 10
- offset: int = 0
- status: str = "active"

Response:
{
  "tenants": [
    {
      "tenant_id": "acme",
      "name": "Acme Corporation",
      "status": "active"
    }
  ],
  "total": 100,
  "limit": 10,
  "offset": 0
}

Implementation Example

File: bast-ai/src/apis/user_management/bast_user_management_api/routers/tenant.py

from fastapi import APIRouter, Depends, HTTPException, Header
from pydantic import BaseModel
from typing import Optional
from ..dependencies import get_current_user, verify_tenant_access

router = APIRouter(prefix="/api/v1/tenants", tags=["tenants"])

class TenantConfigUpdate(BaseModel):
    branding: Optional[dict] = None
    features: Optional[dict] = None

@router.get("/{tenant_id}")
async def get_tenant(
    tenant_id: str,
    x_tenant_id: Optional[str] = Header(None, alias="X-Tenant-ID"),
    current_user: dict = Depends(get_current_user)
):
    """Get tenant information."""
    # Verify tenant access
    if x_tenant_id and x_tenant_id != tenant_id:
        raise HTTPException(status_code=403, detail="Tenant ID mismatch")

    # Verify user has access to tenant
    if not await verify_tenant_access(current_user["id"], tenant_id):
        raise HTTPException(status_code=403, detail="Access denied")

    # Load tenant from database
    tenant = await get_tenant_from_db(tenant_id)
    if not tenant:
        raise HTTPException(status_code=404, detail="Tenant not found")

    return tenant

@router.get("/{tenant_id}/config")
async def get_tenant_config(
    tenant_id: str,
    x_tenant_id: Optional[str] = Header(None, alias="X-Tenant-ID"),
    current_user: dict = Depends(get_current_user)
):
    """Get tenant configuration."""
    # Verify access
    if x_tenant_id and x_tenant_id != tenant_id:
        raise HTTPException(status_code=403, detail="Tenant ID mismatch")

    if not await verify_tenant_access(current_user["id"], tenant_id):
        raise HTTPException(status_code=403, detail="Access denied")

    # Load config
    config = await get_tenant_config_from_db(tenant_id)
    return config

@router.put("/{tenant_id}/config")
async def update_tenant_config(
    tenant_id: str,
    config_update: TenantConfigUpdate,
    x_tenant_id: Optional[str] = Header(None, alias="X-Tenant-ID"),
    current_user: dict = Depends(get_current_user)
):
    """Update tenant configuration."""
    # Verify access
    if x_tenant_id and x_tenant_id != tenant_id:
        raise HTTPException(status_code=403, detail="Tenant ID mismatch")

    if not await verify_tenant_access(current_user["id"], tenant_id):
        raise HTTPException(status_code=403, detail="Access denied")

    # Update config
    updated = await update_tenant_config_in_db(tenant_id, config_update.dict(exclude_unset=True))
    return {"success": True, "updated_at": updated}

User Management API

Endpoints

List Users (Per Tenant)

GET /api/v1/tenants/{tenant_id}/users
Headers: X-Tenant-ID: {tenant_id}, Authorization: Bearer {token}

Query Parameters:
- limit: int = 10
- offset: int = 0
- role: str = None

Response:
{
  "users": [
    {
      "id": "user123",
      "email": "user@example.com",
      "name": "John Doe",
      "role": "admin",
      "status": "active",
      "created_at": "2025-01-01T00:00:00Z"
    }
  ],
  "total": 50,
  "limit": 10,
  "offset": 0
}

Get User

GET /api/v1/tenants/{tenant_id}/users/{user_id}
Headers: X-Tenant-ID: {tenant_id}, Authorization: Bearer {token}

Response:
{
  "id": "user123",
  "email": "user@example.com",
  "name": "John Doe",
  "role": "admin",
  "organization": "acme",
  "tenants": ["acme"],
  "status": "active"
}

Create User

POST /api/v1/tenants/{tenant_id}/users
Headers: X-Tenant-ID: {tenant_id}, Authorization: Bearer {token}

Request Body:
{
  "email": "newuser@example.com",
  "name": "Jane Doe",
  "role": "developer",
  "password": "secure_password"
}

Response:
{
  "id": "user456",
  "email": "newuser@example.com",
  "name": "Jane Doe",
  "role": "developer",
  "organization": "acme",
  "status": "active",
  "created_at": "2025-01-01T00:00:00Z"
}

Update User

PUT /api/v1/tenants/{tenant_id}/users/{user_id}
Headers: X-Tenant-ID: {tenant_id}, Authorization: Bearer {token}

Request Body:
{
  "name": "Jane Smith",
  "role": "admin"
}

Response:
{
  "id": "user456",
  "email": "newuser@example.com",
  "name": "Jane Smith",
  "role": "admin",
  "updated_at": "2025-01-01T00:00:00Z"
}

Delete User

DELETE /api/v1/tenants/{tenant_id}/users/{user_id}
Headers: X-Tenant-ID: {tenant_id}, Authorization: Bearer {token}

Response:
{
  "success": true,
  "deleted_at": "2025-01-01T00:00:00Z"
}

Implementation Example

File: bast-ai/src/apis/user_management/bast_user_management_api/routers/users.py

from fastapi import APIRouter, Depends, HTTPException, Header, Query
from pydantic import BaseModel, EmailStr
from typing import Optional, List
from ..dependencies import get_current_user, verify_tenant_access, verify_user_access

router = APIRouter(prefix="/api/v1/tenants/{tenant_id}/users", tags=["users"])

class UserCreate(BaseModel):
    email: EmailStr
    name: str
    role: str
    password: str

class UserUpdate(BaseModel):
    name: Optional[str] = None
    role: Optional[str] = None
    status: Optional[str] = None

@router.get("")
async def list_users(
    tenant_id: str,
    x_tenant_id: Optional[str] = Header(None, alias="X-Tenant-ID"),
    current_user: dict = Depends(get_current_user),
    limit: int = Query(10, ge=1, le=100),
    offset: int = Query(0, ge=0),
    role: Optional[str] = None
):
    """List users for a tenant."""
    # Verify tenant access
    if x_tenant_id and x_tenant_id != tenant_id:
        raise HTTPException(status_code=403, detail="Tenant ID mismatch")

    if not await verify_tenant_access(current_user["id"], tenant_id):
        raise HTTPException(status_code=403, detail="Access denied")

    # Query users from database (tenant-scoped)
    users = await get_users_from_db(
        tenant_id=tenant_id,
        limit=limit,
        offset=offset,
        role=role
    )

    total = await count_users_in_db(tenant_id=tenant_id, role=role)

    return {
        "users": users,
        "total": total,
        "limit": limit,
        "offset": offset
    }

@router.get("/{user_id}")
async def get_user(
    tenant_id: str,
    user_id: str,
    x_tenant_id: Optional[str] = Header(None, alias="X-Tenant-ID"),
    current_user: dict = Depends(get_current_user)
):
    """Get user information."""
    # Verify tenant access
    if x_tenant_id and x_tenant_id != tenant_id:
        raise HTTPException(status_code=403, detail="Tenant ID mismatch")

    if not await verify_tenant_access(current_user["id"], tenant_id):
        raise HTTPException(status_code=403, detail="Access denied")

    # Load user (verify belongs to tenant)
    user = await get_user_from_db(user_id, tenant_id)
    if not user:
        raise HTTPException(status_code=404, detail="User not found")

    return user

@router.post("")
async def create_user(
    tenant_id: str,
    user_data: UserCreate,
    x_tenant_id: Optional[str] = Header(None, alias="X-Tenant-ID"),
    current_user: dict = Depends(get_current_user)
):
    """Create a new user for a tenant."""
    # Verify tenant access
    if x_tenant_id and x_tenant_id != tenant_id:
        raise HTTPException(status_code=403, detail="Tenant ID mismatch")

    if not await verify_tenant_access(current_user["id"], tenant_id):
        raise HTTPException(status_code=403, detail="Access denied")

    # Check tenant limits
    user_count = await count_users_in_db(tenant_id=tenant_id)
    tenant = await get_tenant_from_db(tenant_id)
    if user_count >= tenant["limits"]["max_users"]:
        raise HTTPException(status_code=403, detail="User limit reached")

    # Create user
    new_user = await create_user_in_db(
        tenant_id=tenant_id,
        email=user_data.email,
        name=user_data.name,
        role=user_data.role,
        password=user_data.password
    )

    return new_user

CAT Management API

Endpoints

List CATs (Per Tenant)

GET /api/v1/tenants/{tenant_id}/cats
Headers: X-Tenant-ID: {tenant_id}, Authorization: Bearer {token}

Response:
{
  "cats": [
    {
      "id": "cat123",
      "prefix": "advisoruat",
      "name": "Advisor UAT",
      "description": "Advisor chatbot for UAT",
      "status": "active",
      "created_at": "2025-01-01T00:00:00Z"
    }
  ],
  "total": 5
}

Get CAT

GET /api/v1/tenants/{tenant_id}/cats/{cat_prefix}
Headers: X-Tenant-ID: {tenant_id}, Authorization: Bearer {token}

Response:
{
  "id": "cat123",
  "prefix": "advisoruat",
  "name": "Advisor UAT",
  "description": "Advisor chatbot for UAT",
  "status": "active",
  "config": {
    "model": "gpt-4",
    "temperature": 0.7
  },
  "created_at": "2025-01-01T00:00:00Z"
}

Create CAT

POST /api/v1/tenants/{tenant_id}/cats
Headers: X-Tenant-ID: {tenant_id}, Authorization: Bearer {token}

Request Body:
{
  "prefix": "newcat",
  "name": "New CAT",
  "description": "New chatbot",
  "config": {
    "model": "gpt-4",
    "temperature": 0.7
  }
}

Response:
{
  "id": "cat456",
  "prefix": "newcat",
  "name": "New CAT",
  "status": "active",
  "created_at": "2025-01-01T00:00:00Z"
}

Implementation Example

File: bast-ai/src/apis/user_management/bast_user_management_api/routers/cats.py

from fastapi import APIRouter, Depends, HTTPException, Header
from pydantic import BaseModel
from typing import Optional
from ..dependencies import get_current_user, verify_tenant_access

router = APIRouter(prefix="/api/v1/tenants/{tenant_id}/cats", tags=["cats"])

class CATCreate(BaseModel):
    prefix: str
    name: str
    description: Optional[str] = None
    config: Optional[dict] = None

@router.get("")
async def list_cats(
    tenant_id: str,
    x_tenant_id: Optional[str] = Header(None, alias="X-Tenant-ID"),
    current_user: dict = Depends(get_current_user)
):
    """List CATs for a tenant."""
    # Verify tenant access
    if x_tenant_id and x_tenant_id != tenant_id:
        raise HTTPException(status_code=403, detail="Tenant ID mismatch")

    if not await verify_tenant_access(current_user["id"], tenant_id):
        raise HTTPException(status_code=403, detail="Access denied")

    # Query CATs from database (tenant-scoped)
    cats = await get_cats_from_db(tenant_id=tenant_id)

    return {
        "cats": cats,
        "total": len(cats)
    }

@router.get("/{cat_prefix}")
async def get_cat(
    tenant_id: str,
    cat_prefix: str,
    x_tenant_id: Optional[str] = Header(None, alias="X-Tenant-ID"),
    current_user: dict = Depends(get_current_user)
):
    """Get CAT information."""
    # Verify tenant access
    if x_tenant_id and x_tenant_id != tenant_id:
        raise HTTPException(status_code=403, detail="Tenant ID mismatch")

    if not await verify_tenant_access(current_user["id"], tenant_id):
        raise HTTPException(status_code=403, detail="Access denied")

    # Load CAT (verify belongs to tenant)
    cat = await get_cat_from_db(cat_prefix, tenant_id)
    if not cat:
        raise HTTPException(status_code=404, detail="CAT not found")

    return cat

@router.post("")
async def create_cat(
    tenant_id: str,
    cat_data: CATCreate,
    x_tenant_id: Optional[str] = Header(None, alias="X-Tenant-ID"),
    current_user: dict = Depends(get_current_user)
):
    """Create a new CAT for a tenant."""
    # Verify tenant access
    if x_tenant_id and x_tenant_id != tenant_id:
        raise HTTPException(status_code=403, detail="Tenant ID mismatch")

    if not await verify_tenant_access(current_user["id"], tenant_id):
        raise HTTPException(status_code=403, detail="Access denied")

    # Check tenant limits
    cat_count = await count_cats_in_db(tenant_id=tenant_id)
    tenant = await get_tenant_from_db(tenant_id)
    if cat_count >= tenant["limits"]["max_cats"]:
        raise HTTPException(status_code=403, detail="CAT limit reached")

    # Check prefix uniqueness
    if await cat_prefix_exists(cat_data.prefix):
        raise HTTPException(status_code=409, detail="CAT prefix already exists")

    # Create CAT
    new_cat = await create_cat_in_db(
        tenant_id=tenant_id,
        prefix=cat_data.prefix,
        name=cat_data.name,
        description=cat_data.description,
        config=cat_data.config
    )

    return new_cat

Data Isolation

Database-Level Isolation

MongoDB Collections

# Tenant-scoped collections
{tenant_id}_users = db[f"{tenant_id}_users"]
{tenant_id}_cats = db[f"{tenant_id}_cats"]

# CAT-scoped collections
{prefix}_cat_data_logs = db[f"{prefix}_cat_data"]["logs"]
{prefix}_cat_data_sessions = db[f"{prefix}_cat_data"]["sessions"]

# Shared collections
auth_db_users = client["auth_db"]["users"]
config_db_tenants = client["config_db"]["tenants"]
config_db_cat_config = client["config_db"]["cat_config"]

Query Filtering

async def get_users_from_db(tenant_id: str, **filters):
    """Get users scoped to tenant."""
    collection = db[f"{tenant_id}_users"]
    query = {"tenant_id": tenant_id, **filters}
    return await collection.find(query).to_list(length=None)

async def get_cat_from_db(cat_prefix: str, tenant_id: str):
    """Get CAT scoped to tenant."""
    collection = db["config_db"]["cat_config"]
    return await collection.find_one({
        "prefix": cat_prefix,
        "tenant_id": tenant_id
    })

API Endpoints

Complete Endpoint List

Tenant Management

Method Endpoint Description Auth Required
GET /api/v1/tenants/{tenant_id} Get tenant Yes
GET /api/v1/tenants/{tenant_id}/config Get tenant config Yes
PUT /api/v1/tenants/{tenant_id}/config Update tenant config Yes
GET /api/v1/tenants List tenants (admin) Admin

User Management

Method Endpoint Description Auth Required
GET /api/v1/tenants/{tenant_id}/users List users Yes
GET /api/v1/tenants/{tenant_id}/users/{user_id} Get user Yes
POST /api/v1/tenants/{tenant_id}/users Create user Yes
PUT /api/v1/tenants/{tenant_id}/users/{user_id} Update user Yes
DELETE /api/v1/tenants/{tenant_id}/users/{user_id} Delete user Yes

CAT Management

Method Endpoint Description Auth Required
GET /api/v1/tenants/{tenant_id}/cats List CATs Yes
GET /api/v1/tenants/{tenant_id}/cats/{cat_prefix} Get CAT Yes
POST /api/v1/tenants/{tenant_id}/cats Create CAT Yes
PUT /api/v1/tenants/{tenant_id}/cats/{cat_prefix} Update CAT Yes
DELETE /api/v1/tenants/{tenant_id}/cats/{cat_prefix} Delete CAT Yes

Authentication & Authorization

Dependency Functions

File: bast-ai/src/apis/user_management/bast_user_management_api/dependencies.py

from fastapi import Depends, HTTPException, Header
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from typing import Optional
import jwt

security = HTTPBearer()

async def get_current_user(
    credentials: HTTPAuthorizationCredentials = Depends(security),
    x_tenant_id: Optional[str] = Header(None, alias="X-Tenant-ID")
) -> dict:
    """Verify JWT token and return user."""
    token = credentials.credentials

    try:
        decoded = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
        user = {
            "id": decoded["id"],
            "email": decoded["email"],
            "organization": decoded.get("organization"),
            "tenants": decoded.get("tenants", [])
        }
        return user
    except jwt.ExpiredSignatureError:
        raise HTTPException(status_code=401, detail="Token expired")
    except jwt.InvalidTokenError:
        raise HTTPException(status_code=401, detail="Invalid token")

async def verify_tenant_access(user_id: str, tenant_id: str) -> bool:
    """Verify user has access to tenant."""
    user = await get_user_from_db(user_id)

    # Check if user belongs to tenant
    if user["organization"] == tenant_id:
        return True

    # Check if user has tenant in tenants list
    if tenant_id in user.get("tenants", []):
        return True

    return False

async def verify_user_access(
    current_user: dict,
    target_user_id: str,
    tenant_id: str
) -> bool:
    """Verify user can access another user."""
    # Users can access themselves
    if current_user["id"] == target_user_id:
        return True

    # Admins can access all users in their tenant
    if current_user.get("role") == "admin":
        return await verify_tenant_access(current_user["id"], tenant_id)

    return False

Error Handling

Standard Error Responses

# 400 Bad Request
{
  "error": "bad_request",
  "message": "Invalid request parameters",
  "details": {}
}

# 401 Unauthorized
{
  "error": "unauthorized",
  "message": "Authentication required"
}

# 403 Forbidden
{
  "error": "forbidden",
  "message": "Access denied for tenant 'acme'"
}

# 404 Not Found
{
  "error": "not_found",
  "message": "Tenant 'acme' not found"
}

# 409 Conflict
{
  "error": "conflict",
  "message": "CAT prefix 'advisoruat' already exists"
}

# 500 Internal Server Error
{
  "error": "internal_error",
  "message": "Internal server error"
}

Implementation Details

Step-by-Step Implementation

Phase 1: Tenant Endpoints (Week 1-2)

  1. Create Tenant Router
  2. Create routers/tenant.py
  3. Implement GET /tenants/{tenant_id}
  4. Implement GET /tenants/{tenant_id}/config
  5. Implement PUT /tenants/{tenant_id}/config

  6. Database Functions

  7. Create tenant database functions
  8. Implement tenant validation
  9. Add tenant caching

Phase 2: User Endpoints (Week 3-4)

  1. Create User Router
  2. Create routers/users.py
  3. Implement CRUD operations
  4. Add tenant scoping

  5. Authorization

  6. Implement tenant access verification
  7. Add role-based access control
  8. Add user limits checking

Phase 3: CAT Endpoints (Week 5-6)

  1. Create CAT Router
  2. Create routers/cats.py
  3. Implement CRUD operations
  4. Add tenant scoping

  5. CAT Configuration

  6. Integrate with config_db
  7. Add CAT validation
  8. Add prefix uniqueness check

Testing Strategy

Unit Tests

# test_tenant_api.py
def test_get_tenant():
    response = client.get("/api/v1/tenants/acme", headers={
        "X-Tenant-ID": "acme",
        "Authorization": f"Bearer {token}"
    })
    assert response.status_code == 200
    assert response.json()["tenant_id"] == "acme"

def test_tenant_access_denied():
    response = client.get("/api/v1/tenants/other", headers={
        "X-Tenant-ID": "other",
        "Authorization": f"Bearer {token}"
    })
    assert response.status_code == 403

Integration Tests

# test_tenant_integration.py
async def test_tenant_user_flow():
    # Create tenant
    tenant = await create_tenant("test")

    # Create user
    user = await create_user(tenant["tenant_id"], "user@test.com")

    # Verify user belongs to tenant
    assert user["organization"] == tenant["tenant_id"]

Deployment

Environment Variables

# Database
MONGODB_URI=mongodb://localhost:27017
MONGODB_AUTH_DB=auth_db
MONGODB_CONFIG_DB=config_db

# Security
JWT_SECRET=your-secret-key
JWT_ALGORITHM=HS256

# API
API_PORT=8001
API_HOST=0.0.0.0

Health Check

@router.get("/health")
async def health_check():
    return {
        "status": "ok",
        "service": "user-management-api",
        "tenant_aware": True,
        "database": await check_database_connection()
    }

Document created: December 16, 2025
Component: Tenant APIs