Skip to content

Set up your platform account and 2FA

Platform-admin accounts are not self-service. Another platform admin must provision yours — there is no /platform/signup route. This mirrors the rule for users (admins create admins, per D78) applied one tier up (D80, D86): the platform tier’s trust model requires a live human to vouch for every account.

Procedure

  1. Request access. Post in #novavms-platform-access tagging the engineering lead. Include: your Novalien email, your expected role (SRE / support / engineer), a short reason ("on-call rotation — Q2 2026" is fine). The lead approves in-thread.

  2. An existing platform admin provisions the account. They log into /platform/login, then use POST /api/v1/platform/users with your email, display name, and a password that satisfies the platform complexity rule (12+ chars, upper + lower + digit + symbol — see cloud/internal/platform/users_handler.go:148-168). Today there is no platform.user_created audit row emitted by the create handler; the only forensic trail is the new row in platform_users (GAP-9-05).

  1. Receive your initial password out-of-band. The provisioning admin uploads the password to a shared 1Password vault path and sends you the item link in Slack DM. No plaintext passwords in chat. If 1Password is unavailable, the fallback is a Signal message — never email, never Slack body. The server stores only the bcrypt hash (cloud/internal/platform/users_handler.go:83-99).

  2. First login. Navigate to https://novavms.novalien.com/platform/login. Sign in with your email and the initial password. If the row was created with password_reset_required = true (the bootstrap path sets this; the manual create path does not), the platform-admin console will direct you to change it.

  1. Change your password. Minimum 12 characters with upper + lower + digit + symbol (users_handler.go:148-168). Store the new password in your own 1Password vault, not the shared one. Delete the initial-password item from the shared vault once you have confirmed sign-in works.

  2. (Future state) Enroll in 2FA. 2FA enrollment + enforcement is in the platform-admin design but not yet shipped in code. The /platform/me/2fa route, TOTP validation in auth_service.go:Login, and the 403 2FA_REQUIRED rejection from mint are all not yet present — see GAP-9-04. When 2FA ships, enrollment is mandatory before your first impersonation mint.

  3. Verify cross-org read access. Navigate to /platform/orgs. You should see the full list of customer orgs (metadata only — name, status, user count, camera count, created_at). The full set of filters described in the PRD (status / plan / created_after / created_before) is not yet wired into the handler (cloud/internal/platform/org_handler.go:47-57 calls ListOrgs with no filter args — GAP-9-06). If the list is empty or returns 403, your account was not granted the platform role correctly — ask the provisioning admin to check.

  1. (Optional) Smoke-test a mint against staging. Mint a 30-minute impersonation token against the novalien-internal-staging org with reason: "onboarding smoke-test". Confirm the red banner appears, confirm your action shows up in both the platform audit log and the staging org’s /admin/audit-log. End the impersonation explicitly when done. This proves the full path works before your first real incident.

Verify

  • /platform/orgs returns the full customer list without 403.
  • /platform/audit-log contains at minimum a platform.login entry for you. Note: platform.login_failed, platform.password_changed, and platform.2fa_enabled audit rows are documented in the long-term design but not yet emitted by code — see GAP-9-08.
  • If you ran step 8, the staging org’s audit log at /admin/audit-log (accessed via that same mint) shows your platform.impersonation_started entry with a Platform Support badge.

If this didn’t work

  • Cannot reach /platform/login — check VPN/Tailscale (on-prem staff only). Platform console is not geo-restricted in prod but may be allowlisted in staging.
  • 401 after login — the provisioning admin set enabled = false or did not commit the insert. Ask them to re-run. The server returns apierror.ErrUnauthorized with the message “invalid platform credentials” (auth_service.go:79) for both wrong-password and disabled-account cases.
  • After 5 failed attempts in 15 minutes the platform account is rate-limited (auth_service.go:66-73). Wait 15 minutes or ask another platform admin to disable the rate-limit row directly in the DB.

See also