Skip to content

Multi-Tenancy

Overview

SaaS-Courier implements Row Level Security (RLS) for tenant isolation in PostgreSQL.


Tenant Resolution

Every authenticated request resolves: - user_id - from JWT sub claim - tenant_id - from JWT tenant_id claim - role - from JWT or database

Important: tenant_id always comes from the JWT, never from request parameters.

Middleware extracts tenant from token:

async def extract_tenant(request: Request) -> UUID:
    token = extract_token_from_header(request)
    payload = decode_jwt(token)
    return UUID(payload["tenant_id"])

Row Level Security (RLS)

All tenant-scoped tables enforce RLS:

ENABLE ROW LEVEL SECURITY;
FORCE ROW LEVEL SECURITY;

CREATE POLICY mandatory_tenant_policy ON shipments
USING (tenant_id = current_setting('app.current_tenant')::uuid)
WITH CHECK (tenant_id = current_setting('app.current_tenant')::uuid);

Context Manager

Use the TenantContext to prevent session leakage:

async def get_shipments(conn, tenant_id: UUID):
    async with TenantContext(tenant_id):
        result = await conn.execute(
            "SELECT * FROM shipments WHERE tenant_id = current_setting('app.current_tenant')::uuid"
        )
    return result

Cross-Tenant Prevention

  1. Queries always filter by tenant_id
  2. Ownership verification before any operation
  3. RLS blocks any cross-tenant access at database level
async def get_shipment(shipment_id: UUID, tenant_id: UUID):
    shipment = await repo.get_by_id(shipment_id)
    if shipment.tenant_id != tenant_id:
        raise PermissionError("Access denied")
    return shipment

Multi-Domain Configuration

DEFAULT_DOMAIN=saas-courier.com
API_DOMAIN=api.saas-courier.com
TRACKING_SUBDOMAIN_PREFIX=tracking

Per-tenant custom domains (loaded from DB):

ROUNDAWAY_EXPRESS_DOMAIN=roundaway-express.com
ROUNDAWAY_EXPRESS_TRACKING_URL=https://track.roundaway-express.com

Rate Limits by Tier

Tier Rate Limit Features
STARTER 100/min Core
GROWTH 500/min + Analytics
SCALE 1000/min + API Access
ENTERPRISE Custom + White-label

API Keys

For SCALE and ENTERPRISE tiers: - Generated per tenant - Stored as hash - Enable ERP/e-commerce integrations