Overview
Mission Control supports three authentication methods:
- Session Cookie - For browser-based access after login
- API Key - For headless automation and CLI tools
- Google OAuth - For team SSO with admin approval workflow
All authenticated users are assigned one of three roles: viewer, operator, or admin.
Authentication Methods
Session Cookie
API Key
Google OAuth
Session Cookie Authentication
Session cookies are set after successful login and valid for 7 days.Login
curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"username": "admin",
"password": "your-secure-password"
}'
Response:{
"user": {
"id": 1,
"username": "admin",
"display_name": "Administrator",
"role": "admin",
"provider": "local",
"created_at": 1709587200,
"last_login_at": 1709673600
}
}
Headers:Set-Cookie: mc-session=a1b2c3d4e5f6...; Path=/; HttpOnly; SameSite=Strict; Max-Age=604800
The mc-session cookie is HttpOnly and cannot be accessed via JavaScript for security.
Using the Session
Include the cookie in subsequent requests:curl http://localhost:3000/api/agents \
-H "Cookie: mc-session=a1b2c3d4e5f6..."
Logout
curl -X POST http://localhost:3000/api/auth/logout \
-H "Cookie: mc-session=a1b2c3d4e5f6..."
API Key Authentication
API keys are for headless automation, CLI tools, and service-to-service communication.Setting Up
Configure your API key in .env:API_KEY=mc_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
Generate a strong random key (at least 32 characters). Never commit API keys to version control.
Using API Keys
Pass the key in the x-api-key header:curl http://localhost:3000/api/agents \
-H "x-api-key: mc_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
Permissions
API key authentication grants admin-level access to all endpoints.{
"id": 0,
"username": "api",
"display_name": "API Access",
"role": "admin"
}
API keys bypass CSRF checks since they’re sent in headers, not cookies.
Google OAuth
Google Sign-In with admin approval workflow for team access.Setup
- Create OAuth credentials in Google Cloud Console
- Configure redirect URI:
https://your-domain.com/api/auth/google
- Add credentials to
.env:
GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=your-client-secret
OAuth Flow
User clicks 'Sign in with Google'
Browser redirects to Google’s OAuth consent screen
User grants permission
Google redirects back to /api/auth/google?code=...&state=...
Server exchanges code for tokens
Mission Control validates the code and creates a pending access request
Admin approves request
Admin reviews the request in the dashboard and assigns a role
User can log in
User is notified and can access the dashboard
Callback Endpoint
GET /api/auth/google?code=...&state=...
Response: 302 redirect to dashboard or access request pageManaging Access Requests
List pending requests (admin only):curl http://localhost:3000/api/auth/access-requests \
-H "x-api-key: your-api-key"
Response:{
"requests": [
{
"id": 1,
"username": "[email protected]",
"email": "[email protected]",
"reason": "Need access to monitor agents",
"status": "pending",
"created_at": 1709587200
}
]
}
Approve a request:curl -X POST http://localhost:3000/api/auth/access-requests \
-H "Content-Type: application/json" \
-H "x-api-key: your-api-key" \
-d '{
"id": 1,
"action": "approve",
"role": "operator"
}'
Role-Based Access Control (RBAC)
Mission Control enforces three permission levels:
{
"role": "viewer",
"permissions": [
"Read agents",
"Read tasks",
"Read token usage",
"Read logs and activities",
"Read system status"
],
"restrictions": [
"Cannot create or modify resources",
"Cannot access admin settings",
"Cannot manage users"
]
}
Role Hierarchy
Roles are hierarchical: viewer < operator < admin
const ROLE_LEVELS = {
viewer: 0,
operator: 1,
admin: 2
};
Endpoints specify minimum required role. For example, POST /api/agents requires operator or higher.
Security Considerations
Follow these security best practices before deploying to production:
Password Requirements
- Minimum 12 characters
- Hashed with scrypt (CPU-intensive key derivation)
- Constant-time comparison to prevent timing attacks
// From auth.ts:208
if (password.length < 12) {
throw new Error('Password must be at least 12 characters');
}
Session Security
- Duration: 7 days (604800 seconds)
- Storage: SQLite
user_sessions table
- Token: 32-byte random hex (64 characters)
- Cleanup: Expired sessions purged on each login
// From auth.ts:80
const SESSION_DURATION = 7 * 24 * 60 * 60; // 7 days
const token = randomBytes(32).toString('hex');
API Key Security
- Constant-time comparison prevents timing attacks
- Never log API keys in application logs
- Rotate keys regularly
- Use different keys for dev/staging/production
// From auth.ts:281
if (apiKey && safeCompare(apiKey, process.env.API_KEY || '')) {
return { id: 0, username: 'api', role: 'admin' };
}
CSRF Protection
Mutating requests validate the Origin header:
// From proxy.ts:74-88
if (['POST', 'PUT', 'DELETE', 'PATCH'].includes(method)) {
const origin = request.headers.get('origin');
if (origin) {
const originHost = new URL(origin).host;
const requestHost = request.headers.get('host');
if (originHost !== requestHost) {
return NextResponse.json(
{ error: 'CSRF origin mismatch' },
{ status: 403 }
);
}
}
}
API key authentication bypasses CSRF checks since keys are header-based.
User Management
Get Current User
curl http://localhost:3000/api/auth/me \
-H "x-api-key: your-api-key"
Response:
{
"user": {
"id": 1,
"username": "admin",
"display_name": "Administrator",
"role": "admin",
"workspace_id": 1,
"provider": "local",
"email": null,
"avatar_url": null,
"created_at": 1709587200,
"last_login_at": 1709673600
}
}
List Users (Admin)
curl http://localhost:3000/api/auth/users \
-H "x-api-key: your-api-key"
Response:
{
"users": [
{
"id": 1,
"username": "admin",
"display_name": "Administrator",
"role": "admin",
"created_at": 1709587200
},
{
"id": 2,
"username": "operator1",
"display_name": "Agent Operator",
"role": "operator",
"created_at": 1709673600
}
]
}
Create User (Admin)
curl -X POST http://localhost:3000/api/auth/users \
-H "Content-Type: application/json" \
-H "x-api-key: your-api-key" \
-d '{
"username": "analyst",
"password": "secure-password-min-12-chars",
"display_name": "Data Analyst",
"role": "viewer",
"email": "[email protected]"
}'
Response: 201 Created
{
"user": {
"id": 3,
"username": "analyst",
"display_name": "Data Analyst",
"role": "viewer",
"email": "[email protected]",
"created_at": 1709760000
}
}
Update User (Admin)
curl -X PUT http://localhost:3000/api/auth/users \
-H "Content-Type: application/json" \
-H "x-api-key: your-api-key" \
-d '{
"id": 3,
"role": "operator",
"display_name": "Senior Data Analyst"
}'
Delete User (Admin)
curl -X DELETE http://localhost:3000/api/auth/users \
-H "Content-Type: application/json" \
-H "x-api-key: your-api-key" \
-d '{"id": 3}'
Deleting a user destroys all their sessions immediately.
Error Responses
401 Unauthorized
Authentication required but not provided:
{
"error": "Authentication required"
}
Causes:
- No session cookie or API key provided
- Session expired (7 days)
- Invalid API key
403 Forbidden
Authenticated but insufficient permissions:
{
"error": "Requires admin role or higher"
}
Causes:
- Viewer trying to create resources
- Operator trying to manage users
- OAuth user not yet approved
409 Conflict
Resource already exists:
{
"error": "Username already exists"
}
Initial Setup
On first run, Mission Control seeds an admin user from environment variables:
# .env
AUTH_USER=admin
AUTH_PASS=your-secure-password
# Or use base64 if password contains special characters
AUTH_PASS_B64=eW91ci1zZWN1cmUtcGFzc3dvcmQ=
If AUTH_PASS contains # or other shell metacharacters, use quotes or switch to AUTH_PASS_B64.
Generating a Secure Password
# Generate 24-character random password
openssl rand -base64 24
# For base64 encoding
echo -n "your-password" | base64
Best Practices
Use Strong Credentials
- Passwords: Minimum 12 characters, mix of letters/numbers/symbols
- API keys: At least 32 random characters
- Rotate API keys quarterly
Deploy Behind Reverse Proxy
Use Caddy, nginx, or Traefik with automatic TLS:server {
listen 443 ssl http2;
server_name mission-control.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Configure Host Allowlist
Restrict network access in production:MC_ALLOWED_HOSTS=mission-control.example.com,*.internal.corp
Enable Audit Logging
Track administrative actions:curl http://localhost:3000/api/audit \
-H "x-api-key: your-api-key"
Next Steps
Agents API
Manage agent lifecycle and status
Tasks API
Create and assign tasks to agents
Webhooks
Configure outbound event notifications
Token Tracking
Monitor LLM token usage and costs