Skip to main content

Account security model

Every Orbit organization controls its own security posture: two-factor enrollment, step-up re-authentication, backup codes, a per-role 2FA requirement, and the audit trail that records each transition. Orbit exposes these as tenant-owned controls — none of them are platform mandates, and the defaults are open. This page explains how the pieces fit; the mechanics of each endpoint are in Settings endpoints.

Layers of the model

Three layers separate concern. Dashboard sign-in. Email and password (or SAML, where enabled) authenticate the person. The credential vocabulary — session tokens vs API keys vs the SCIM token — and how each request’s class resolves is owned by Authentication and session model. API-key access. Server-to-server integrations use dv_-prefixed keys, rotated in place with grace windows. That lifecycle lives in API key lifecycle and rotation. The org security posture. This page. Everything layered on top of sign-in for the people in your organization: TOTP 2FA, step-up challenges that gate sensitive mutations, backup codes, a per-role require-2FA policy, password rotation signals, and the audit trail every transition writes.

TOTP 2FA

Each member enrolls a time-based one-time password (TOTP) authenticator in the dashboard under Settings → Security. The authenticator secret lives with the auth provider; Orbit’s API wraps enrollment status, disable, and backup codes behind step-up-gated routes. Two facts matter about how disabling works:
  1. Disabling is a full removal, not a flag flip. When a disable succeeds, Orbit removes the enrolled authenticator factor and the backup-code factor at the provider — a leftover factor can otherwise be re-presented as a second factor the user can never satisfy.
  2. Backup codes are single-use recovery codes. The status endpoint (GET /api/v1/settings/security/2fa/backup-codes/status) returns only whether codes exist and how many remain — never the codes themselves. Regenerating a set (POST /api/v1/settings/security/2fa/backup-codes/regenerate) returns the new codes exactly once and invalidates the prior set the same instant, so an attacker inside a stolen session cannot quietly take over the recovery path.

Step-up challenges

2FA disable and backup-code regeneration are gated by a step-up challenge, not by session recency alone. A live browser session is proof of possession, not proof of identity — so before either mutation runs, Orbit asks for a fresh credential: the current password OR a current TOTP code. The sequence: The minted token is single-use, expires five minutes after mint, and binds to exactly one operation (disable or regenerate_backup_codes). Tokens live in a dedicated step-up namespace; legacy re-auth tokens minted on session-recency alone can never satisfy a 2FA-mutating endpoint. A missing, expired, or wrong-op token returns 401 REAUTH_REQUIRED.

Org-wide require-2FA

An owner can require a second factor for any subset of roles through GET/POST /api/v1/settings/security/require-2fa. The policy is a bitmap over the five roles — owner, admin, developer, viewer, billing — and each role flips independently. Requiring a role blocks its members from the dashboard until they enroll a second factor; the /me response carries the enrollment redirect so the blocked member knows where to land. Unset roles stay not-required, and the read returns the full map so you can round-trip. Two guards keep the policy safe to roll out:
  • Self-lockout guard. An owner cannot enable owner=true while their own account has no enrolled second factor — the write is rejected with a 422 explaining why.
  • Role-at-a-time merge. The write merges a partial bitmap, so the dashboard can toggle one role without re-sending the whole map.
A staged rollout works well: announce to the team, enforce role by role (usually admins and developers first, viewers last), then audit the trail. The policy is a default-off, tenant-owned control — Orbit does not mandate it for any organization.

Password policy and session audit

Password rotation is recorded the same way 2FA transitions are. The dashboard’s change-password card rotates the credential and then records the rotation server-side via POST /api/v1/settings/security/password-changed, which fans out a security-critical “your password was changed” alert — a bell-row in the Notification Center, email, and mobile push — with the requester IP and user-agent attached. A genuine rotation therefore never passes silently. The dashboard Settings → Security page is the single surface where all of this is visible: your own 2FA enrollment and backup-code status, the org’s per-role require-2FA toggles (owner-only write), session management, and the SSO/SCIM panels — which keep their own pages (SAML/SCIM federation).

Audit trail

Every security transition — a granted or failed step-up challenge, a disable, a backup-code regeneration, a require-2FA bitmap change, a password rotation — writes an audit record with the requester IP and user-agent. The out-of-band alerts (bell, email, push) are the user-visible half; the audit trail is the tamper-evident half. For a SOC 2-style review, the events group like this: Each of those rows answers the two questions an auditor always asks: who changed it, and from where.