Multi-Tenant Auth & Quotas
Technical breakdown of JWT authentication, Role-Based Access Control, API key encryption, Redis Quota Manager, plan tiers, and bonus systems.
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
- User submits credentials to
/api/v1/auth/token. - Server validates via
verify_password(plain, hashed)using bcrypt. - Returns
{"access_token": ..., "refresh_token": ..., "token_type": "bearer"}. - Subsequent requests extract the token via
OAuth2PasswordBearer(tokenUrl="/api/v1/token"). validate_token()decodes and verifies the JWT, raising401 Unauthorizedon 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 forrequire_admin_roledependency 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_idmatches 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"):
- Builds quota key:
f"{feature}_per_{period}"(e.g.,run_backtest_per_day). - Looks up limit from
self.plan["quotas"].get(quota_key):None= no quota defined โ skip this period.0= feature is forbidden โ returnFalse.-1= unlimited โ skip (continues to check other periods).
- Redis Key Structure:
usage:{user_id}:{quota_key}:{date_str}with auto-expiring TTL.
| Period | Key Date Format | TTL |
|---|---|---|
| Day | %Y-%m-%d | Until end of day |
| Week | %Y-%m-%d (start of week Monday) | Until end of week (Sunday) |
| Month | %Y-%m | Until end of month |
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
| Feature | Free | Standard | Pro |
|---|---|---|---|
| Live Strategies | 1 | 5 | Unlimited |
| Backtests/Day | 3 | 20 | Unlimited |
| Genetic Runs | 0 | 2/week | Unlimited |
| AI Assistant | No | Yes | Yes |
| Max Symbols | 3 | 15 | Unlimited |
| Market Types | Spot | Spot + Futures | All |
| Exchange Support | Bybit only | All | All + Custom |
Plan Enforcement Points
Throughout the API, plans gate access via decorators and dependency checks:
| Check | Purpose |
|---|---|
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 |
FastAPI REST Routes
Comprehensive overview of the FastAPI application, modular router architecture, all 22+ route modules, the Redis command bus, security middleware, and rate limiting.
WebSocket Real-Time Events
Technical details of the ASGI WebSocket server โ connection lifecycle, JWT authentication, channel authorization via regex patterns, Redis Pub/Sub stream forwarding, and graceful cleanup.