Skip to content

03 - Login And Broker Flow

Two Authentication Layers

Tradeboard separates the local application session from the broker session.

  1. The user authenticates to the self-hosted app with username/password and optional TOTP.
  2. The user selects a broker and completes that broker's auth flow, or resumes an existing valid broker token.
  3. External /api/v1 clients use the Tradeboard API key, which resolves the active broker token server-side.

A broker token can expire while the app cookie remains valid. In that state the UI must offer broker reconnect rather than hard-logging the user out.

App Login

blueprints/auth.py owns setup, password login, TOTP promotion, session status, password changes, and logout. Successful login can resume an existing broker session through _try_resume_broker_session; otherwise it sends the user to broker selection.

When login TOTP is required, the password step stores a short-lived pending_totp_user rather than establishing session["user"]. A correct /auth/login/totp request promotes it to an authenticated session and records totp_verified_at for sensitive downstream authorization such as Remote MCP write consent.

Broker Discovery And Auth

utils/plugin_loader.py reads broker/*/plugin.json and lazy-loads broker.<key>.api.auth_api. Generic callbacks are handled by blueprints/brlogin.py; specialized routes support brokers that need extra OTP, TOTP, or credential steps.

The current plugin inventory is 36: 34 securities brokers, Delta Exchange for crypto derivatives, and a Dhan sandbox plugin for paper trading. Authentication shape varies by broker, and capability metadata is the correct way for UI code to discover supported exchanges and features.

Token Storage

DataStorage behavior
PasswordArgon2 hash in the user database
Tradeboard API keyArgon2+pepper verification hash and encrypted retrievable value
Broker auth/feed tokensFernet ciphertext derived from installation secrets
TOTP secretEncrypted at rest
Browser sessionSigned Flask session cookie with host-dependent secure flags

upsert_auth() compares decrypted old and new broker/feed tokens. Fernet encryption is nondeterministic, so ciphertext comparison would be wrong. If the token, feed token, broker, and revoke state are unchanged, a resumed login does not tear down the shared broker WebSocket feed.

Multi-Session Model

Tradeboard allows up to five active app sessions for the single configured user. A new row replaces an existing row for the same username and IP; at the cap, the oldest row is removed. Every device shares the installation's one active broker session and server-side market-data feed.

The SPA polls /auth/session-status. That route refreshes the current active_sessions.last_seen at most once every 30 seconds and reports the current active-session count.

Broker Expiry And Reconnect

If session status finds a valid app session but no active broker token, it returns:

json
{
  "status": "success",
  "authenticated": true,
  "logged_in": true,
  "broker_session_expired": true
}

It intentionally preserves the app session. Protected dashboard APIs can then return the broker-expired state and the frontend can route the user through /auth/broker again.

Revocation Events

  • Explicit logout removes the device session and clears the browser session.
  • Daily session-expiry handling revokes broker access according to configuration.
  • Password change clears every active app session, emits force_logout, and clears the current cookie.
  • Unchanged multi-device broker resume preserves the shared feed.

See 40 Logout And Session Lifecycle for the expiry and heartbeat state machine.

Key Files

FilePurpose
blueprints/auth.pyApp login, TOTP, session APIs, logout
blueprints/brlogin.pyBroker callbacks and special login helpers
blueprints/broker_credentials.pyCredential and capability APIs
database/auth_db.pyBroker tokens, API keys, active sessions, login audit
utils/plugin_loader.pyPlugin discovery and lazy auth loading
utils/session.pyProtected-route session validity
frontend/src/components/auth/AuthSync.tsxBackend-to-Zustand session synchronization