diff --git a/docs.json b/docs.json index 89a03e6b..163f094f 100644 --- a/docs.json +++ b/docs.json @@ -256,7 +256,8 @@ "docs/features/structured", "docs/features/mini", "docs/features/autoagents", - "docs/features/onboard" + "docs/features/onboard", + "docs/features/gateway-bind-aware-auth" ] }, { diff --git a/docs/features/chat.mdx b/docs/features/chat.mdx index f91c996d..b29a5453 100644 --- a/docs/features/chat.mdx +++ b/docs/features/chat.mdx @@ -112,8 +112,38 @@ start_chat_server(config=config) |----------|-------------|---------| | `PRAISONAI_CHAT_PORT` | Server port | `8000` | | `PRAISONAI_CHAT_HOST` | Server host | `0.0.0.0` | +| `CHAINLIT_HOST` | Host the UI binds to (drives auth mode) | `127.0.0.1` | +| `CHAINLIT_USERNAME` | Username for authentication | `admin` | +| `CHAINLIT_PASSWORD` | Password for authentication | `admin` | +| `PRAISONAI_ALLOW_DEFAULT_CREDS` | Allow admin/admin on external bind (unsafe) | `false` | | `CHAINLIT_AUTH_SECRET` | Auth secret for sessions | Auto-generated | +--- + +## Security + +The chat UI enforces bind-aware authentication — stricter security when bound to external interfaces. + +| Interface | Security Mode | Credentials | +|-----------|---------------|------------| +| **Loopback** (`127.0.0.1`, `localhost`) | Permissive | `admin/admin` allowed | +| **External** (`0.0.0.0`, LAN, public) | Strict | Custom credentials required | + + +Using default `admin/admin` credentials on external interfaces will cause a `UIStartupError` unless `PRAISONAI_ALLOW_DEFAULT_CREDS=1` is set (demo only). + + +```bash +# Safe for external deployment +export CHAINLIT_USERNAME=myuser +export CHAINLIT_PASSWORD=mypass +praisonai chat --host 0.0.0.0 +``` + + + Complete security configuration guide + + ## UI Features ### Chain of Thought Visualization diff --git a/docs/features/gateway-bind-aware-auth.mdx b/docs/features/gateway-bind-aware-auth.mdx new file mode 100644 index 00000000..a8308434 --- /dev/null +++ b/docs/features/gateway-bind-aware-auth.mdx @@ -0,0 +1,219 @@ +--- +title: "Bind-Aware Authentication" +sidebarTitle: "Bind-Aware Auth" +description: "Gateway and UI automatically enforce stricter auth when bound to external interfaces" +icon: "shield" +--- + +The gateway and chat UI change security behavior based on the interface they bind to — permissive on loopback, strict on external. + +```mermaid +graph LR + subgraph "Bind-Aware Auth" + Bind[🔌 Bind Host] --> Check{🔍 Loopback?} + Check -->|Yes 127.0.0.1| Local[🟢 local mode
no token required] + Check -->|No 0.0.0.0| Token[🔒 token mode
auth required] + end + + classDef bind fill:#6366F1,stroke:#7C90A0,color:#fff + classDef decision fill:#F59E0B,stroke:#7C90A0,color:#fff + classDef permissive fill:#10B981,stroke:#7C90A0,color:#fff + classDef strict fill:#8B0000,stroke:#7C90A0,color:#fff + + class Bind bind + class Check decision + class Local permissive + class Token strict +``` + +## Quick Start + + + +```python +from praisonaiagents import Agent + +agent = Agent( + name="Local Agent", + instructions="You are a helpful assistant.", +) + +# Serve via gateway on loopback — no token needed +# $ praisonai gateway start --host 127.0.0.1 +agent.start("hello") +``` + + + +```bash +# Option A: Run onboarding (recommended) +praisonai onboard + +# Option B: Set a token explicitly +export GATEWAY_AUTH_TOKEN=$(openssl rand -hex 16) +praisonai gateway start --host 0.0.0.0 +``` + + + +--- + +## How It Works + +```mermaid +sequenceDiagram + participant User + participant Gateway + participant BindAwareAuth + participant WS as WebSocket Clients + + User->>Gateway: praisonai gateway start --host + Gateway->>BindAwareAuth: assert_external_bind_safe(config) + alt H is loopback (127.0.0.1, localhost, ::1) + BindAwareAuth-->>Gateway: OK (permissive, warn if no token) + else H is external (0.0.0.0, LAN, public) + alt auth_token set + BindAwareAuth-->>Gateway: OK (strict) + else no token + BindAwareAuth-->>Gateway: raise GatewayStartupError + Gateway-->>User: exit 1 + fix instructions + end + end + Gateway->>WS: accept connections +``` + +| Mode | Meaning | Trigger | +|---|---|---| +| `local` | Permissive — no token required | Loopback bind (default) | +| `token` | Token required (auto-generated if absent on loopback) | External bind (default) | +| `password` | Username/password auth | Chainlit UI | +| `trusted-proxy` | Auth handled upstream | Reverse proxy setups | + +--- + +## Interface Detection + +| Host | `is_loopback()` | Resolved mode | +|---|---|---| +| `127.0.0.1` | `True` | `local` | +| `127.255.255.255` | `True` | `local` | +| `localhost` | `True` | `local` | +| `::1` | `True` | `local` | +| `0.0.0.0` | `False` | `token` | +| `192.168.1.x` | `False` | `token` | +| `10.0.0.x` | `False` | `token` | +| `8.8.8.8` (public) | `False` | `token` | + +--- + +## User Flows + +**Flow A — "I want a quick local demo":** Run on `127.0.0.1`, no config needed. Token auto-generated, fingerprint logged (`gw_****abcd`), saved to `~/.praisonai/.env`. + +**Flow B — "I want to share on my LAN":** Run `praisonai onboard` (30s, 3 prompts) OR `export GATEWAY_AUTH_TOKEN=$(openssl rand -hex 16)` → `praisonai gateway start --host 0.0.0.0`. + +**Flow C — "I'm deploying to a VPS":** Same as B, but also set `CHAINLIT_USERNAME` / `CHAINLIT_PASSWORD` for the UI, and consider TLS. + +**Flow D — "Lab/demo — I accept the risk of admin/admin on external":** `export PRAISONAI_ALLOW_DEFAULT_CREDS=1`. + +--- + +## Environment Variables + +| Variable | Scope | Effect | +|---|---|---| +| `GATEWAY_AUTH_TOKEN` | Gateway | Auth token. Required on external bind. Auto-generated + saved to `~/.praisonai/.env` (mode `0600`) on loopback when unset. | +| `CHAINLIT_HOST` | UI | Host the UI binds to (default `127.0.0.1`). Drives UI auth mode resolution. | +| `CHAINLIT_USERNAME` | UI | Username (default `admin`). | +| `CHAINLIT_PASSWORD` | UI | Password (default `admin`). | +| `PRAISONAI_ALLOW_DEFAULT_CREDS` | UI | Escape hatch. Set to `1`/`true`/`yes` to allow `admin/admin` on external bind. **Unsafe — demo only.** | +| `CHAINLIT_AUTH_SECRET` | UI | Session secret. Auto-generated if unset (ephemeral per-process). | + +--- + +## Error Reference + +**`GatewayStartupError`** — raised by `assert_external_bind_safe()` when binding externally without a token: +``` +Cannot bind to 0.0.0.0 without an auth token. +Fix: praisonai onboard (30 seconds, 3 prompts) +Or: export GATEWAY_AUTH_TOKEN=$(openssl rand -hex 16) +``` + +**`UIStartupError`** — raised by `register_password_auth()` when `admin/admin` used on external bind: +``` +Cannot bind to 0.0.0.0 with default admin/admin credentials. +Fix: export CHAINLIT_USERNAME=myuser CHAINLIT_PASSWORD=mypass +Lab: export PRAISONAI_ALLOW_DEFAULT_CREDS=1 (demo only) +``` + +--- + +## Token Fingerprinting + +Logs now show `gw_****XXXX` (last 4 chars), never the raw token. This is implemented by `get_auth_token_fingerprint()` for safe logging. Retrieve the full token from `~/.praisonai/.env` if needed. + +--- + +## Which Option When + +```mermaid +graph TB + Q{Where will it run?} + Q -->|My laptop only| Local[127.0.0.1 — just run it] + Q -->|LAN for my team| LAN{Have a token?} + Q -->|Public internet| Public[0.0.0.0 + token + TLS + custom creds] + LAN -->|No| Onboard[praisonai onboard] + LAN -->|Yes| Export[export GATEWAY_AUTH_TOKEN=...] + + classDef question fill:#F59E0B,stroke:#7C90A0,color:#fff + classDef safe fill:#10B981,stroke:#7C90A0,color:#fff + classDef action fill:#189AB4,stroke:#7C90A0,color:#fff + classDef strict fill:#8B0000,stroke:#7C90A0,color:#fff + + class Q,LAN question + class Local safe + class Onboard,Export action + class Public strict +``` + +--- + +## Best Practices + + + +Prefer `praisonai onboard` over manual token creation. It handles all the setup automatically and saves the token securely. + + + +The auto-generated `.env` file contains sensitive tokens. Add it to your `.gitignore` and never commit it to version control. + + + +Always set `CHAINLIT_USERNAME` and `CHAINLIT_PASSWORD` before binding to external interfaces. Never use `admin/admin` in production. + + + +The `PRAISONAI_ALLOW_DEFAULT_CREDS=1` escape hatch should only be used for ephemeral demos or testing. Never in production. + + + +--- + +## Related + + + + Core gateway functionality and configuration + + + Quick setup with automatic token generation + + + Common gateway issues and solutions + + + Chainlit UI security and configuration + + \ No newline at end of file diff --git a/docs/features/onboard.mdx b/docs/features/onboard.mdx index d74d095b..99bc9c72 100644 --- a/docs/features/onboard.mdx +++ b/docs/features/onboard.mdx @@ -116,9 +116,13 @@ When onboarding completes successfully, the wizard installs: |-----------|----------|---------| | **Platform daemon** | System service (launchd/systemd/Windows Task) | Keeps bot running in background | | **Bot configuration** | `~/.praisonai/config/` | Stores tokens and settings | -| **Gateway auth token** | `~/.praisonai/.env` (env var `GATEWAY_AUTH_TOKEN`) | Authentication for web dashboard | +| **Gateway auth token** | `~/.praisonai/.env` (mode `0600`) | Authentication for web dashboard | | **Dashboard URL** | Printed in Done panel | Local web interface | + +Auth token is now auto-persisted to `~/.praisonai/.env` with secure permissions (mode `0600`) and shown as fingerprint `gw_****XXXX` in logs for security. + + --- ## The ✅ Done Panel @@ -356,6 +360,10 @@ If bots aren't responding or services seem down, run `praisonai doctor` for diag + + Gateway and UI security behavior based on bind interface + + --- ## Related diff --git a/docs/gateway.mdx b/docs/gateway.mdx index be6234d7..ea590e9e 100644 --- a/docs/gateway.mdx +++ b/docs/gateway.mdx @@ -89,6 +89,36 @@ sequenceDiagram --- +## Authentication + +Authentication posture changes automatically based on the bind interface. + +```mermaid +graph LR + Check{🔍 Interface} + Check -->|127.0.0.1| Local[🟢 Permissive
No token required] + Check -->|0.0.0.0| External[🔒 Strict
Token required] + + classDef decision fill:#F59E0B,stroke:#7C90A0,color:#fff + classDef permissive fill:#10B981,stroke:#7C90A0,color:#fff + classDef strict fill:#8B0000,stroke:#7C90A0,color:#fff + + class Check decision + class Local permissive + class External strict +``` + +| Interface | Mode | Auth Required | +|-----------|------|---------------| +| **Loopback** (`127.0.0.1`, `localhost`, `::1`) | Permissive | No | +| **External** (`0.0.0.0`, LAN IPs, public IPs) | Strict | Yes | + + + Complete authentication security guide + + +--- + ## Configuration Options diff --git a/docs/guides/troubleshoot-gateway.mdx b/docs/guides/troubleshoot-gateway.mdx index 43db5abc..db3e1aee 100644 --- a/docs/guides/troubleshoot-gateway.mdx +++ b/docs/guides/troubleshoot-gateway.mdx @@ -300,6 +300,69 @@ Should show daemon running and gateway reachable. --- +## Authentication Errors + +### GatewayStartupError: Cannot bind to 0.0.0.0 without an auth token + +**Symptom:** Gateway fails to start when binding to external interfaces without authentication. + + + +```bash +praisonai onboard +``` +This automatically generates and saves a secure token. + + + +```bash +export GATEWAY_AUTH_TOKEN=$(openssl rand -hex 16) +praisonai gateway start --host 0.0.0.0 +``` + + + +### UIStartupError: Cannot bind to 0.0.0.0 with default admin/admin credentials + +**Symptom:** Chainlit UI fails to start on external interface with default credentials. + + + +```bash +export CHAINLIT_USERNAME=myuser +export CHAINLIT_PASSWORD=mypass +praisonai chat --host 0.0.0.0 +``` + + + +```bash +export PRAISONAI_ALLOW_DEFAULT_CREDS=1 +praisonai chat --host 0.0.0.0 +``` + + + +### My gateway logs show `gw_****xxxx` instead of the full token + +This is intentional for security — tokens are fingerprinted in logs to prevent exposure. + + + +```bash +cat ~/.praisonai/.env | grep GATEWAY_AUTH_TOKEN +``` + + + +```bash +echo $GATEWAY_AUTH_TOKEN +``` + + + +--- + ## Restart After Config Change When you update bot configuration files, restart the daemon using these OS-specific commands (matching the onboard Done panel):