-
-
Notifications
You must be signed in to change notification settings - Fork 119
Login & Auth
CortexPrism supports two authentication methods: username+password login for the web UI, and
API token authentication for programmatic access. Both flow through the extractIdentity()
function in src/server/auth.ts and produce a RequestIdentity used by authorization guards.
┌─────────────────────────────────────────────────────┐
│ Incoming Request │
└────────────────────────┬────────────────────────────┘
│
▼
┌─────────────────────┐
│ extractIdentity() │
└─────────┬───────────┘
│
┌─────────────┼─────────────┐
▼ │ ▼
Authorization: │ Session Cookie
Bearer <token> │ cortex_session
│ │ │
▼ │ ▼
validateApiToken() │ validateSession()
SHA-256 hash match │ in-memory Map lookup
│ │ │
└──────────────┼─────────────┘
│
▼
┌─────────────────────┐
│ getUserTeams() │
│ isInstanceAdmin() │
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ RequestIdentity │
│ { type, userId, │
│ username, │
│ teamIds, │
│ isInstanceAdmin } │
└─────────────────────┘
The login page at /login (src/server/ui/pages/login.ts) presents a form with username and
password fields. On submit, it calls POST /api/auth/login.
POST /api/auth/login
Content-Type: application/json
{
"username": "alice",
"password": "mypassword"
}
Multi-user path: When username is provided, verifyUserPassword() queries the users table,
retrieves the stored PBKDF2-SHA-256 hash and salt, recomputes the hash, and compares using
constant-time comparison. On success, a session is created with userId and username set.
Legacy path: When username is omitted, the system falls back to the vault-stored single
password (__cortex_web_password) for backward compatibility.
Rate limiting: Both paths are rate-limited by client IP via checkAuthRateLimit(), returning
HTTP 429 after too many attempts.
Response (200):
{
"success": true,
"sessionId": "550e8400-...",
"user": {
"id": "usr_550e8400-...",
"username": "alice"
}
}The response includes a Set-Cookie header with the cortex_session cookie.
Passwords must be at least 8 characters with at least 2 of:
- Lowercase letters (
a-z) - Uppercase letters (
A-Z) - Numbers (
0-9) - Symbols (non-alphanumeric)
Passwords are hashed using PBKDF2 with:
- Hash: SHA-256
- Iterations: 200,000
- Salt: 16 bytes of cryptographically random data
- Key length: 32 bytes (256 bits)
// src/server/auth.ts
const PBKDF2_ITERATIONS = 200_000;
const KEY_LENGTH = 32;
const SALT_LENGTH = 16;Include the token in the Authorization header:
Authorization: Bearer cortex_token_550e8400-...
The extractIdentity() function:
- Parses the
Authorizationheader - Strips the
Bearerprefix - Computes SHA-256 hash of the token
- Looks up the hash in the
user_tokenstable - Validates expiration and revocation status
- Fetches the user's teams and admin status
- Returns a
RequestIdentitywithtype: 'user'
See API Tokens for full token management documentation.
Sessions are stored in an in-memory Map<string, Session> with a 7-day TTL:
const SESSION_DURATION_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
interface Session {
id: string;
userId?: string;
username?: string;
createdAt: string;
expiresAt: string;
lastActivity: string;
ipAddress?: string;
userAgent?: string;
}The cortex_session cookie is set with:
- HttpOnly: prevents JavaScript access
- Secure: when the request is over HTTPS
-
Path:
/ - Max-Age: 7 days
-
SameSite:
Strict
validateSession() checks the session ID against the in-memory map and verifies the expiry.
On each validation, lastActivity is updated. Expired sessions are automatically removed from the map.
POST /api/auth/logout
Destroys the session from the in-memory map and clears the session cookie.
extractIdentity() in src/server/auth.ts extracts identity from either an API token or
session cookie:
async function extractIdentity(req: Request): Promise<RequestIdentity> {
// 1. Check Authorization: Bearer header
// 2. Validate API token (SHA-256 hash lookup)
// 3. Fall back to session cookie (cortex_session)
// 4. Return anonymous if neither is valid
}The returned RequestIdentity includes:
-
type:'user'|'instance'|'anonymous' -
userId,username: user details -
teamIds: all teams the user belongs to -
currentTeamId: fromx-cortex-teamheader or first team -
isInstanceAdmin: whether the user is an instance admin -
sessionId: web session ID (when authenticated via cookie)
requireAuth() in src/server/auth.ts is the main auth guard used by the router:
- If
webAuth.requireAuthisfalse, allow all requests as instance identity - If vault key is not configured, return 503
- If no users exist (first run), allow as instance identity
- Extract identity via
extractIdentity() - If identity is
userorinstance, allow - Otherwise, return 401 with
{ error: "Authentication required", loginUrl: "/login" }
GET /api/auth/status
Returns the current authentication state:
{
"authenticated": true,
"user": {
"id": "usr_550e8400-...",
"username": "alice",
"teams": ["team_abc123"],
"currentTeam": "team_abc123",
"isInstanceAdmin": false
},
"hasPassword": true,
"requireAuth": true
}When not authenticated:
{
"authenticated": false,
"hasPassword": true,
"requireAuth": true
}cortex login # Interactive login with username + password
cortex login --token <token> # Login with an API token directly
cortex login --host <url> # Specify server URL (default: http://localhost:11434)
cortex logout # Clear stored auth token from ~/.cortex/auth.json
cortex whoami # Show current authenticated user and teamsPrompts for username and password, then calls POST /api/auth/login. On success, displays
the authenticated user. Note: web sessions are ephemeral — use cortex login --token <token>
with an API token for persistent CLI authentication.
Saves the API token to ~/.cortex/auth.json for persistent authentication across CLI sessions.
The server URL can be overridden with --host or the CORTEX_API_URL environment variable.
Calls GET /api/auth/status with the stored token and displays:
- Username and user ID
- Team memberships
- Instance admin status (if applicable)
Removes ~/.cortex/auth.json, clearing the stored API token.
The Login page (/login) is rendered by src/server/ui-auth.ts using the page template in
src/server/ui/pages/login.ts. It provides:
- Username and password fields
- Submit button that calls
POST /api/auth/login - Redirect to the main UI on success
- Error display on failed login
The header (src/server/ui/shell.ts) includes a team selector dropdown for switching
between teams, rendered when the user belongs to multiple teams.
- Passwords are never stored in plaintext — only PBKDF2-derived hashes
- Session cookies are HttpOnly and SameSite=Strict to prevent XSS and CSRF attacks
- API token hashes cannot be reversed to recover the plaintext token
- Rate limiting is applied to login endpoints by client IP
- Disabled users cannot authenticate even with correct credentials
- Revoked API tokens are rejected by
validateApiToken()
- API Tokens — Token creation, management, and revocation
- Multi-User Collaboration — Users, teams, authorization guards
- Federation — Instance-to-instance pairing tokens
- Security Model — Parallax security architecture
CortexPrism — Open-source AI agent operating system · Discord · Apache 2.0 License · Built with Deno 2.x + TypeScript
- Agent Loop
- Built-in Agents
- Metacognition
- Memory System
- Skills System
- Sub-Agents
- Built-in Tools
- Code Intelligence
- Code Sandbox
- Cross-Agent Context Protocol
- Prompt Lab
- PKM Assistant
- Voice Pipeline
- Computer Use
- Browser Tool
- Git & GitHub
- Scheduler & Jobs
- Dashboard
- Observability
- A2A Protocol
- MCP Gateway
- Distributed Nodes
- Memori Checkpoints
- Eval System
- Workflow Engine
- Triggers
- Projects
- TUI
- Glossary
- Update System
- Chrome Bridge
- Swarm
- AgentLint
- Model Benchmarking
- Smart Context
- Cost Optimizer