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):