Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/builderz-labs/mission-control/llms.txt

Use this file to discover all available pages before exploring further.

Mission Control implements multiple layers of security to protect sensitive agent orchestration data, API keys, and user credentials. This guide covers authentication methods, role-based access control (RBAC), network security, and deployment best practices.

Authentication

Mission Control supports multiple authentication methods:

Session-Based Authentication

The primary authentication method uses secure HTTP-only cookies with cryptographically random session tokens. Login flow:
  1. User submits credentials to /api/auth/login
  2. Server validates credentials using constant-time comparison (timing attack prevention)
  3. On success, creates session token (32-byte random hex) with 7-day expiration
  4. Returns mc-session cookie with httpOnly, secure (in production), and sameSite=strict flags
  5. Subsequent requests include session cookie for authentication
Session security features (src/lib/auth.ts:104-121):
const SESSION_DURATION = 7 * 24 * 60 * 60 // 7 days
const token = randomBytes(32).toString('hex')
  • Cryptographic randomness: Uses Node.js crypto.randomBytes(32) for unpredictable tokens
  • Automatic expiration: Sessions expire after 7 days
  • Cleanup: Expired sessions are purged on new session creation
  • IP & User-Agent tracking: Sessions log IP address and user agent for audit trails

API Key Authentication

For headless/programmatic access, use API key authentication:
curl -H "x-api-key: your-api-key" https://mc.example.com/api/...
Security implementation (src/proxy.ts:100-106):
const apiKey = request.headers.get('x-api-key')
if (apiKey && safeCompare(apiKey, process.env.API_KEY || '')) {
  return applySecurityHeaders(NextResponse.next())
}
  • Constant-time comparison: Uses crypto.timingSafeEqual() to prevent timing attacks
  • Admin privileges: API key grants full admin access (synthetic user with role: 'admin')
  • Single key: One API key per instance (rotate regularly)
Generate a strong API key with high entropy:
openssl rand -hex 32
Never commit API_KEY to version control.

Google OAuth (Optional)

Mission Control supports Google Sign-In with approval workflow:
  1. User clicks “Sign in with Google”
  2. Google OAuth flow validates user identity
  3. Admin approval required: New Google users are created with is_approved=0
  4. Admin approves user via UI or API
  5. User can then access the dashboard
Configuration:
GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
NEXT_PUBLIC_GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
Create OAuth credentials in Google Cloud Console and configure authorized origins/redirect URIs.

Role-Based Access Control (RBAC)

Mission Control implements a three-tier role hierarchy:
RoleLevelPermissions
viewer0Read-only access to dashboards, logs, and metrics
operator1Viewer permissions + trigger pipelines, manage agents, modify configurations
admin2Operator permissions + user management, system settings, API key access
Role enforcement (src/lib/auth.ts:300-319):
const ROLE_LEVELS: Record<string, number> = { viewer: 0, operator: 1, admin: 2 }

export function requireRole(
  request: Request,
  minRole: User['role']
): { user: User } | { error: string; status: 401 | 403 } {
  const user = getUserFromRequest(request)
  if (!user) {
    return { error: 'Authentication required', status: 401 }
  }
  if ((ROLE_LEVELS[user.role] ?? -1) < ROLE_LEVELS[minRole]) {
    return { error: `Requires ${minRole} role or higher`, status: 403 }
  }
  return { user }
}
API routes use requireRole() to enforce minimum role requirements:
// Example: /api/users (admin only)
const auth = requireRole(request, 'admin')
if ('error' in auth) {
  return NextResponse.json({ error: auth.error }, { status: auth.status })
}
const user = auth.user

Managing Users

Admins can manage users via the UI or API:
curl -X POST https://mc.example.com/api/users \
  -H "x-api-key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "operator1",
    "password": "strong-password-min-12-chars",
    "display_name": "Operator One",
    "role": "operator"
  }'
Password minimum length: 12 characters (enforced in src/lib/auth.ts:208)

Network Access Control

Mission Control implements default-deny host-based access control in production environments.

How It Works (src/proxy.ts:56-70)

const hostName = getRequestHostname(request) // From x-forwarded-host or host header
const allowAnyHost = envFlag('MC_ALLOW_ANY_HOST') || process.env.NODE_ENV !== 'production'
const allowedPatterns = String(process.env.MC_ALLOWED_HOSTS || '')
  .split(',')
  .map((s) => s.trim())
  .filter(Boolean)

const isAllowedHost = allowAnyHost || allowedPatterns.some((p) => hostMatches(p, hostName))

if (!isAllowedHost) {
  return new NextResponse('Forbidden', { status: 403 })
}
Behavior:
  • Development (NODE_ENV !== 'production'): All hosts allowed by default
  • Production (NODE_ENV === 'production'): Only hosts matching MC_ALLOWED_HOSTS patterns are allowed
  • Override: Set MC_ALLOW_ANY_HOST=true to disable (not recommended in production)

Allowed Host Patterns

Supports flexible pattern matching (src/proxy.ts:28-46):
PatternExampleMatchesDoes NOT Match
Exact hostapp.example.comapp.example.comapi.example.com, app.example.com:8080
Subdomain wildcard*.example.comapi.example.com, app.example.comexample.com (bare domain)
Prefix wildcard100.*100.64.0.1, 100.100.100.10010.0.0.1
Example configuration:
MC_ALLOWED_HOSTS=localhost,127.0.0.1,mc.example.com,*.internal.example.com,100.*
This allows:
  • localhost and 127.0.0.1 (local development/testing)
  • mc.example.com (production domain)
  • api.internal.example.com, dashboard.internal.example.com (internal subdomains)
  • 100.64.0.1, 100.100.100.100 (Tailscale IP range)
Always configure MC_ALLOWED_HOSTS in production to prevent unauthorized access from spoofed Host headers.Never set MC_ALLOW_ANY_HOST=true in production unless absolutely necessary.

CSRF Protection

Mission Control validates the Origin header for state-changing requests (src/proxy.ts:74-88):
const method = request.method.toUpperCase()
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')?.split(',')[0]?.trim()
    if (originHost && requestHost && originHost !== requestHost) {
      return NextResponse.json({ error: 'CSRF origin mismatch' }, { status: 403 })
    }
  }
}
Protection:
  • Validates Origin header matches Host header for POST/PUT/DELETE/PATCH requests
  • Prevents cross-site request forgery attacks
  • Works automatically with modern browsers

Security Headers

All responses include security headers (src/proxy.ts:48-53):
function applySecurityHeaders(response: NextResponse): NextResponse {
  response.headers.set('X-Content-Type-Options', 'nosniff')
  response.headers.set('X-Frame-Options', 'DENY')
  response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin')
  return response
}
HeaderValuePurpose
X-Content-Type-OptionsnosniffPrevent MIME type sniffing attacks
X-Frame-OptionsDENYPrevent clickjacking (no iframe embedding)
Referrer-Policystrict-origin-when-cross-originLimit referrer information leakage
Recommended reverse proxy headers (add via Nginx/Caddy):
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';" always;

TLS / HTTPS

Always deploy Mission Control behind a reverse proxy with TLS in production.Never expose the Node.js server directly to the internet.

Enable Secure Cookies

When serving over HTTPS, enable secure cookies:
MC_COOKIE_SECURE=true
This sets the Secure flag on session cookies, preventing transmission over unencrypted HTTP. Default behavior:
  • Production (NODE_ENV=production): secure=true unless explicitly set to false
  • Development: secure=false (allows testing over HTTP)

Reverse Proxy TLS Termination

See Production Deployment - Reverse Proxy Configuration for Nginx/Caddy/Traefik examples with:
  • TLS 1.2/1.3 only
  • Strong cipher suites
  • HSTS (Strict-Transport-Security)
  • HTTP to HTTPS redirect

Password Security

Mission Control uses industry-standard password hashing:
  • Algorithm: Argon2id (via @node-rs/argon2 or fallback to bcrypt)
  • Verification: Constant-time comparison to prevent timing attacks
  • Minimum length: 12 characters (enforced at user creation)
Password with special characters: If AUTH_PASS contains #, use one of these methods:
# Method 1: Quote the value
AUTH_PASS="my#password"

# Method 2: Base64 encoding
AUTH_PASS_B64=$(echo -n 'my#password' | base64)

Secrets Management

Never commit .env files to version control.The repository .gitignore already excludes these files:
  • .env
  • .env.local
  • .env.production

Best Practices

  1. Use environment-specific files:
    • Development: .env.local
    • Production: .env or secret management service
  2. Rotate credentials regularly:
    # Generate new API key
    openssl rand -hex 32
    
    # Update AUTH_PASS for admin
    openssl rand -base64 32
    
  3. Use secret management services:
    • Docker Swarm: Docker Secrets
    • Kubernetes: Sealed Secrets or External Secrets Operator
    • Cloud: AWS Secrets Manager, Azure Key Vault, Google Secret Manager
  4. Restrict file permissions:
    chmod 600 /opt/mission-control/.env
    chown mission-control:mission-control /opt/mission-control/.env
    

1Password Integration

Mission Control supports pulling secrets from 1Password CLI:
OP_VAULT_NAME=production
The Integrations panel can fetch secrets from the specified vault.

Gateway Security

Device Identity & WebCrypto

Mission Control uses WebCrypto for device identity signing when connecting to gateways:
Device identity requires a secure context (HTTPS or localhost).If you see “Gateway error: device identity required”, ensure Mission Control is served over HTTPS.

Gateway Origin Allowlist

Configure your OpenClaw gateway to allow Mission Control origins:
openclaw.json
{
  "gateway": {
    "controlUi": {
      "allowedOrigins": ["https://mc.example.com"]
    }
  }
}
Restart the gateway after updating the configuration.

Audit Logging

Mission Control logs security-relevant events:
  • User authentication: Login attempts, session creation/destruction
  • User management: User creation, role changes, deletions
  • API access: API key usage with IP address and user agent
  • Configuration changes: System settings modifications
Retention:
MC_RETAIN_AUDIT_DAYS=365  # Keep audit logs for 1 year
See Environment Variables - Data Retention.

Security Checklist

1

Authentication

  • Set strong AUTH_PASS (min 12 characters, high entropy)
  • Generate secure API_KEY with openssl rand -hex 32
  • Rotate credentials on initial deployment
  • Enable Google OAuth approval workflow if using SSO
2

Network Security

  • Configure MC_ALLOWED_HOSTS to restrict access
  • Deploy behind reverse proxy (Nginx/Caddy)
  • Enable TLS with valid certificates (Let’s Encrypt)
  • Set MC_COOKIE_SECURE=true for HTTPS
  • Configure firewall to allow only necessary ports
3

Access Control

  • Assign users appropriate roles (viewer/operator/admin)
  • Regularly review user list and remove inactive accounts
  • Use API key only for automation (not humans)
  • Enable 2FA for admin accounts (if using Google OAuth)
4

Data Protection

  • Restrict .env file permissions (chmod 600)
  • Keep .env out of version control
  • Use secret management service in production
  • Configure audit log retention (MC_RETAIN_AUDIT_DAYS=365)
5

Monitoring

  • Monitor authentication failures
  • Alert on unauthorized access attempts (403 errors)
  • Review audit logs regularly
  • Track API key usage patterns

Reporting Vulnerabilities

If you discover a security vulnerability in Mission Control:
Do not open a public issue.Email security@builderz.dev with:
  • Description of the vulnerability
  • Steps to reproduce
  • Potential impact
  • Suggested fix (if any)
We will acknowledge receipt within 48 hours and aim to provide a fix within 7 days for critical issues.

Additional Resources

Build docs developers (and LLMs) love