> For the complete documentation index, see [llms.txt](https://docs.openalgo.in/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.openalgo.in/developers/design-documentation/api-layer.md).

# 03 - Login and Broker Login Flow

## Two Authentication Layers

OpenAlgo 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 OpenAlgo 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

| Data                    | Storage behavior                                                |
| ----------------------- | --------------------------------------------------------------- |
| Password                | Argon2 hash in the user database                                |
| OpenAlgo API key        | Argon2+pepper verification hash and encrypted retrievable value |
| Broker auth/feed tokens | Fernet ciphertext derived from installation secrets             |
| TOTP secret             | Encrypted at rest                                               |
| Browser session         | Signed 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

OpenAlgo 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](/developers/design-documentation/40-logout-and-session-expiry.md) for the expiry and heartbeat state machine.

## Key Files

| File                                        | Purpose                                               |
| ------------------------------------------- | ----------------------------------------------------- |
| `blueprints/auth.py`                        | App login, TOTP, session APIs, logout                 |
| `blueprints/brlogin.py`                     | Broker callbacks and special login helpers            |
| `blueprints/broker_credentials.py`          | Credential and capability APIs                        |
| `database/auth_db.py`                       | Broker tokens, API keys, active sessions, login audit |
| `utils/plugin_loader.py`                    | Plugin discovery and lazy auth loading                |
| `utils/session.py`                          | Protected-route session validity                      |
| `frontend/src/components/auth/AuthSync.tsx` | Backend-to-Zustand session synchronization            |
