API and SaaS Layer

Multi-Tenant Auth & Quotas

Technical breakdown of JWT authentication, Role-Based Access Control, API key encryption, Redis Quota Manager, plan tiers, and bonus systems.

โฑ๏ธ 6 min read๐Ÿ“Š Level: Intermediate

DepthSight is built out-of-the-box as a multi-user SaaS platform. To isolate execution environments and limit resource abuse, the system integrates a strict security and quota enforcement system spanning JWT auth, Fernet encryption, Redis rate counters, and hot-reloadable plan configurations.


JWT Authentication and RBAC

The security layer (api/security.py, ~163 lines) uses JSON Web Tokens (JWT) for authentication with HS256 signing.

Token Creation

Sources:

Two token types are issued:

  • Access Token (15 min default): Used for REST API authentication via Authorization: Bearer <token>.
  • Refresh Token (30 days): Used for silent re-authentication without requiring login.

Both tokens contain sub (username), exp (expiration), and type (access/refresh) claims.

Authentication Flow

  1. User submits credentials to /api/v1/auth/token.
  2. Server validates via verify_password(plain, hashed) using bcrypt.
  3. Returns {"access_token": ..., "refresh_token": ..., "token_type": "bearer"}.
  4. Subsequent requests extract the token via OAuth2PasswordBearer(tokenUrl="/api/v1/token").
  5. validate_token() decodes and verifies the JWT, raising 401 Unauthorized on failure.

Role-Based Access Control

Two roles are supported:

  • user: Default role. Can manage own strategies, backtests, API keys.
  • admin: Elevated role for system administration. Required for require_admin_role dependency on admin routers.

Role is extracted from the JWT payload and checked via FastAPI dependency injection at the router level.

Workspace Isolation

The extracted user_id is automatically injected into:

  • Database queries: Every CRUD operation filters by user_id.
  • Redis channel paths: Each user's state keys are namespaced as depthsight:state:{user_id}:*.
  • WebSocket subscriptions: Channel authorization verifies user_id matches the channel owner.

This ensures no user can read another user's strategies, logs, API keys, or active positions.


API Key Encryption

Exchange API keys are encrypted at rest using Fernet symmetric encryption via cryptography.fernet with MultiFernet for key rotation support.

Key Loading (lines 111โ€“132)

Sources:

Encryption/Decryption

Sources:

A SHA-256 hash of each API key is stored in the api_keys.api_key_hash column for deduplication, ensuring the same key cannot be registered twice. Only the hash (not the plaintext) is used for lookups.


Redis Quota Manager

The QuotaManager (api/quota_manager.py, ~140 lines) limits user resource usage in real-time, preventing users on free or standard plans from overloading the server with backtest tasks or running too many parallel bots.

Architecture

User Request -> API Endpoint -> QuotaManager.check_and_consume(feature)
                                   |
                                   โ”œโ”€ _check_standard_quotas(feature)
                                   |     โ”œโ”€ Iterates day/week/month periods
                                   |     โ”œโ”€ Looks up limit from plan config
                                   |     โ””โ”€ Checks Redis counter
                                   |
                                   โ”œโ”€ If no standard quota -> check bonuses
                                   |
                                   โ””โ”€ If no bonus -> unlimited (True)

Standard Quota Check (_check_standard_quotas, lines 52โ€“108)

For each of three periods ("day", "week", "month"):

  1. Builds quota key: f"{feature}_per_{period}" (e.g., run_backtest_per_day).
  2. Looks up limit from self.plan["quotas"].get(quota_key):
    • None = no quota defined โ†’ skip this period.
    • 0 = feature is forbidden โ†’ return False.
    • -1 = unlimited โ†’ skip (continues to check other periods).
  3. Redis Key Structure: usage:{user_id}:{quota_key}:{date_str} with auto-expiring TTL.
PeriodKey Date FormatTTL
Day%Y-%m-%dUntil end of day
Week%Y-%m-%d (start of week Monday)Until end of week (Sunday)
Month%Y-%mUntil end of month
Sources:

Bonus System

If no standard plan limit is defined for a specific action, the manager checks a PostgreSQL table for one-off "bonus units":

Sources:

Bonuses are used for custom backtest packages, promotional credits, or affiliate rewards.


Plan Tier System

Plan tiers are defined in api/plans_config.yml and loaded via a PlansConfig class with hot-reload support โ€” it checks file modification time (st_mtime_ns) on every access, allowing plan changes without restarting the server.

Core Plan Features

FeatureFreeStandardPro
Live Strategies15Unlimited
Backtests/Day320Unlimited
Genetic Runs02/weekUnlimited
AI AssistantNoYesYes
Max Symbols315Unlimited
Market TypesSpotSpot + FuturesAll
Exchange SupportBybit onlyAllAll + Custom

Plan Enforcement Points

Throughout the API, plans gate access via decorators and dependency checks:

CheckPurpose
require_permission("use_ai_assistant")AI Co-Pilot access gate
_enforce_live_strategy_limit()Max concurrent running strategies
_check_symbol_permissions()Symbol whitelist enforcement
_enforce_backtest_engine_access()Engine type restrictions (Fast vs Event-Driven)
_check_intracandle_trigger_permission()Intra-candle trigger access for Pro plans