Authentication
Orbital has two separate authentication systems: platform authentication for infrastructure management and orb-level authentication for application users.
Authentication Architecture
Section titled “Authentication Architecture”Platform Authentication (Infrastructure)
Section titled “Platform Authentication (Infrastructure)”Purpose: Manage the Orbital platform itself - create/manage orbs
Storage: NATS KV buckets (platform_admins, platform_invitations, platform_credentials)
Routes: /api/_auth/*
Bootstrap: Auto-creates invitation on startup if no admins exist
CLI: orbital admin login/register/logout/status
Platform admins are infrastructure operators who manage orbs via /api/_orbs endpoints.
Orb-Level Authentication (Application)
Section titled “Orb-Level Authentication (Application)”Purpose: Application-level users (operators, players, etc.)
Storage: NATS entries within orb (e.g., accounts/operators)
Routes: /api/{orbId}/*
Bootstrap: Orb-specific (e.g., access.init primitive)
CLI: orbital auth <orbId>/signin or browser at /api/<orbId>/signin
Orb users access application-specific APIs defined by the orb’s schemas and primitives.
This page focuses on platform authentication. For orb-level auth implementation, see Passkey Authentication Flow.
Platform Admin Passkey Flows
Section titled “Platform Admin Passkey Flows”Registration (First-Time Platform Admin)
Section titled “Registration (First-Time Platform Admin)”sequenceDiagram
participant Admin
participant Browser
participant API
participant Device
Admin->>Browser: Follow invitation link or CLI
Browser->>API: POST /api/_auth/passkey/begin?invite={code}
API->>Browser: Challenge + Session ID
Browser->>Device: Create passkey
Device->>Admin: Biometric prompt
Admin->>Device: Authenticate
Device->>Browser: Signed credential
Browser->>API: POST /api/_auth/passkey/complete
API->>Browser: Success + Platform JWT
Login (Subsequent Platform Admin Login)
Section titled “Login (Subsequent Platform Admin Login)”sequenceDiagram
participant Admin
participant Browser
participant API
participant Device
Admin->>Browser: Click "Sign in" or orbital admin login
Browser->>API: POST /api/_auth/passkey/begin
API->>Browser: Challenge + Session ID
Browser->>Device: Sign challenge
Device->>Admin: Biometric prompt
Admin->>Device: Authenticate
Device->>Browser: Signed response
Browser->>API: POST /api/_auth/passkey/complete
API->>Browser: Success + Platform JWT
Browser implementation (platform admin)
Section titled “Browser implementation (platform admin)”Register a new platform admin
Section titled “Register a new platform admin”import { startRegistration } from '@simplewebauthn/browser';
// Step 1: Begin registration with invitationconst invitationCode = 'abc123xyz';const beginResponse = await fetch(`/api/_auth/passkey/begin`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ invite: invitationCode }),});
const { sessionId, options } = await beginResponse.json();
// Step 2: Create credential with deviceconst credential = await navigator.credentials.create({ publicKey: options.publicKey });
// Step 3: Complete registrationconst completeResponse = await fetch('/api/_auth/passkey/complete', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ sessionId, credential: /* formatted credential */ }),});
const { token, admin } = await completeResponse.json();// Store token for authenticated requests to /api/_orbsAuthenticate with existing passkey
Section titled “Authenticate with existing passkey”import { startAuthentication } from '@simplewebauthn/browser';
// Step 1: Begin loginconst beginResponse = await fetch('/api/_auth/passkey/begin', { method: 'POST', headers: { 'Content-Type': 'application/json' },});
const { sessionId, options } = await beginResponse.json();
// Step 2: Sign challenge with deviceconst credential = await navigator.credentials.get({ publicKey: options.publicKey });// Step 3: Complete loginconst completeResponse = await fetch('/api/_auth/passkey/complete', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ sessionId, assertion: /* formatted credential */ }),});
const { token, admin } = await completeResponse.json();// Token is used for /api/_orbs management endpointsBootstrap Mode (First-Time Platform Setup)
Section titled “Bootstrap Mode (First-Time Platform Setup)”When deploying Orbital for the first time with no platform admins, the system enters bootstrap mode to allow initial admin registration.
How Bootstrap Works
Section titled “How Bootstrap Works”- Server starts with no platform admins → creates bootstrap invitation automatically
- Bootstrap invitation logged to console with token and signin URL
- Invitation endpoints accessible without authentication (only in bootstrap mode)
- First admin registers using invitation token → bootstrap mode disabled
- Management endpoints (
/api/_orbs) now require platform admin JWT
Using the CLI
Section titled “Using the CLI”The recommended way to bootstrap:
# 1. List invitations (no authentication required in bootstrap mode)orbital invite ls
# Output:# ● abc123xyz# Status: active# Expires: 2025-01-12T10:30:00Z
# 2. Register with invitation token (opens browser)orbital admin register abc123xyz
# Browser opens → complete passkey registration → first platform admin created
# 3. Authenticate the CLIorbital admin login
# 4. Verify authenticationorbital admin statusUsing curl
Section titled “Using curl”For programmatic access:
# Get bootstrap invitation (works in bootstrap mode - no auth required)curl https://your-api.com/api/_auth/invitations
# Response:# [# {# "token": "abc123xyz",# "status": "active",# "createdAt": "2025-01-05T10:30:00Z",# "expiresAt": "2025-01-12T10:30:00Z"# }# ]Then open the registration URL in a browser:
https://your-api.com/api/_auth/signin?invite=abc123xyzSecurity Model
Section titled “Security Model”Bootstrap mode is safe because:
- ✅ Empty system - No data exists to protect when adminCount = 0
- ✅ Invitation ≠ access - Still requires passkey registration (phishing-resistant)
- ✅ Self-disabling - Endpoints return 401 after first admin exists
- ✅ Time-limited - Bootstrap invitations expire in 7 days
- ✅ Audit trail - All bootstrap access attempts are logged
- ✅ NATS-native - All data stored in NATS KV buckets, no external database
Key difference from previous approach: No bootstrap secret header needed. The system simply checks admin count - if zero, allow unauthenticated access to invitation listing. This is simpler and just as secure.
Deployment Considerations
Section titled “Deployment Considerations”Development/Staging:
# Start serverdocker compose up -d./orbital serve
# Check logs for bootstrap invitation# 2025-01-05T10:30:00Z WARN platform bootstrap mode reason="no admins found"# 2025-01-05T10:30:00Z WARN invitation created code=abc123xyz expires=7d# 2025-01-05T10:30:00Z WARN register at url=http://localhost:52000/api/_auth/signin?invite=abc123xyzProduction:
# Same process, bootstrap invitation logged./orbital serve
# Admin uses CLI from secure workstationorbital invite lsorbital admin register <token>orbital admin loginFor high-security environments, monitor logs for bootstrap invitation generation and immediately use it to create the first admin.
Platform JWT Structure
Section titled “Platform JWT Structure”Platform admin JWTs include:
{ "sub": "admin-id-xid", "name": "Admin Name", "type": "platform", "iat": 1704451200, "exp": 1704537600}The type: "platform" field distinguishes platform JWTs from orb-level JWTs.
Orb-Level Authentication
Section titled “Orb-Level Authentication”For application-level authentication (operators, players), orbs use the access domain primitive:
kind: Orbid: accountsuses: - service: access handlers: [passkey, invitations, bootstrap]modules: - id: operators schemas: - id: operator fields: [email, displayName, roles]Users access orb signin at /api/accounts/signin - completely separate from platform auth.
Next steps
Section titled “Next steps”- Orb-level auth implementation: Passkey Authentication Flow
- Passkey setup guide: Passkey Setup Guide
- CLI commands: CLI Reference
- Platform architecture: Platform Overview