TurboPanel Docs
Using TurboPanel

Account security

Your account is one identity across every organization you belong to, and the ways you prove it is you are managed in one place: the account menu → Security (/account/security). This chapter covers signing in, the second factor, passkeys, linked sign-in providers, password rules and recovery. Configuring which providers a control plane offers is the operator's side, in Accounts and access.

The model

An account has an email address and up to four ways in:

Way inWhat it isSecond factor?
PasswordEmail + password, the way every account starts (except one created by GitHub or Google sign-in).Yes, when two-factor is on.
Two-factor codeA six-digit code from an authenticator app, or one of ten one-time backup codes, asked for after the password.— it is the second factor.
PasskeyA WebAuthn credential (Touch ID, Windows Hello, a security key, a phone) registered from a browser.No — a passkey sign-in never asks for a code; the passkey is the second factor.
Linked providerA GitHub or Google identity linked to this account.Yes, when two-factor is on: the code step follows the provider round trip.

Three rules run through everything below:

  1. Changing how you sign in needs a fresh proof. Enrolling or disabling two-factor, regenerating backup codes, adding or removing a passkey, and unlinking a provider all require re-authentication. An account that has a password must type it into the Current password field every time — a fresh session does not substitute. An account with no password (it signs in only with a passkey or a linked provider) is let through on a session younger than 15 minutes. Otherwise the request is refused (403) and the app asks for the password. Linking a provider is the one exception: it is a redirect and cannot carry a password, so it always uses the 15-minute window.
  2. Securing the account signs everyone else out. Each of those changes revokes every other session on the account and keeps only the one that made the change. A password reset revokes all sessions, including the one at the keyboard.
  3. You cannot remove your last way in. Unlinking the only provider on an account that has no password and no passkey is refused (last_sign_in_method). Keep at least two ways in before removing one.

Sessions last 7 days and are cookie-bound to the control plane's origin; the native apps use the same session against the control plane you connected to (Change control plane on the sign-in screen).

Sign in

Email and password → Sign In. On a control plane with providers configured, Sign in with GitHub / Sign in with Google sit beside it, and Sign in with a passkey below.

If two-factor is on, the authentication code step follows: six digits from your app, or Use a backup code to type one of the ten. The challenge lives 5 minutes. Five wrong codes within 15 minutes lock two-factor sign-in for that account until the 15 minutes are up; signing in again does not reset the count. Each code works once: a code that already signed you in is refused, even under a new challenge, so wait for the next one from your app.

A new account made by sign-up must verify its email first (the link in the mail is good for 24 hours); until then sign-in is refused with Verify your email before signing in. A control plane without outbound email skips verification entirely.

Forgot your password

On the sign-in screen, Forgot password? sits under the password field.

Enter your account's email and choose Send reset link. The answer is always Check your inbox, whether or not an account uses that address, so the screen never tells a stranger which emails have accounts.

If the address belongs to an active account that has a password, an email arrives with a link that is good for one hour.

The link opens Reset Password: choose a New password (the same rules as everywhere, see Passwords). The page says Your password has been changed and signs you out on every device: sign in again with the new password.

A link that is expired, already used or unknown opens This reset link doesn't work anymore with Request a new link. A control plane that cannot send email cannot send the link, so the email never arrives there.

Turn on two-factor

Security → Two-factor authentication → Enable two-factor.

Enter your current password (re-authentication).

Add this to your authenticator: scan the QR code, or Copy key / Copy link (the base32 secret or the otpauth:// URI) into any TOTP app.

Type the first six-digit Authentication code and Verify and enable. Nothing is enabled until a code verifies.

Save your backup codes. Ten one-time codes, shown once. Copy all, store them where you can reach them without this device, then I've saved these. They are the only way back in if you lose the authenticator.

Afterwards the app shows the method and how many backup codes remain. Regenerate backup codes issues ten new ones and invalidates the old set; Disable two-factor removes the authenticator and the codes. Both re-authenticate.

Add a passkey

Security → Passkeys → Add a passkey. Web only in this release — the native apps show a use a browser note instead of a button, because a passkey must be created on the control plane's own origin.

Enter your current password if asked, and give the passkey a name (the device or authenticator it lives on).

Complete the browser's prompt. User verification is required — a fingerprint, face, device PIN or security-key PIN, not just a touch.

The list shows each passkey's name, when it was added, and where it lives — Synced (a multi-device credential backed up by its provider), Multi-device, or This device only. Remove re-authenticates; a passkey registered twice is refused (passkey_exists).

To sign in with it: Sign in with a passkey on the sign-in screen — no email, no password, no code.

Security → Linked accounts. Only providers the control plane has configured appear. Linking is web-only (Link from a browser on native). Finish the provider round trip in the same browser that started it: the return trip is refused on any other.

Link next to the provider. Your session must be younger than 15 minutes (otherwise Sign in again to link an account).

Authorize at the provider. You return to Security with Account linked.

TurboPanel stores the provider identity only — no provider tokens. A provider identity already linked to a different user is refused (That provider account is already linked to another user). Unlink re-authenticates and is refused when it would leave no way in.

No linking by email address

Signing in with a provider whose identity is linked to no account never joins an existing account just because the email matches. It creates a new account when sign-up is open, or fails with New accounts cannot be created this way when it is closed. A new account also needs an email the provider has verified; otherwise sign-up is refused (oauth_email_unverified). Link from the signed-in Security screen instead.

Passwords

The same rule is enforced on every path that sets a password (install, sign-up, reset): at least 8 characters, at most 256, at least one number, at least one of $ ! @ % & * # ^ ( ) _ + = -, and no leading or trailing space. Every one of those paths also refuses a password that appears in a known data breach (password_breached); see Password safety.

Change your password

Account menu → Security → Change password (signed in; an account that has a password).

Type your Current password, then the New password (at least 8 characters, a number and a symbol, no space at either end) and Confirm new password.

Change password. The screen says Password changed — Every other device was signed out. This one stays signed in.

The current password is checked first, and wrong guesses are limited like every other password check (5 a minute). A new password must differ from the current one and must not be a known breached password. An account that signs in only with a passkey or a linked provider has no password to change, and there is no screen to set one yet (no_password).

Permanent actions

An organization owner can turn on Manage Organization → Security → Ask people to confirm it is them before permanent actions. It is off by default; turning it on is recommended, and the change is recorded in the audit trail. When it is on, these actions each ask the person for proof first:

  • delete a project, an environment, a server, a managed database, or a database inside one;
  • remove a member from the organization (or leave it);
  • revoke a license key, or a server's key.

The app opens Confirm it is you and asks for your password, or the 6-digit authentication code from your authenticator app if two-factor is on. Once confirmed, the action goes through, and every permanent action on that sign-in is unlocked for five minutes; signing in counts as a confirmation, so nobody is asked straight after signing in. An account with neither a password nor an authenticator (passkey or provider sign-in only) is told to sign in again, then repeat the action.

Over the API the first call answers 403 reauth_required with the action, the methods accepted (password, totp or signin) and windowSeconds. Prove it with POST /auth/reauth ({ "password": "…" } or { "code": "…" }), which answers expiresAt, then repeat the call. A wrong proof is Reauthentication failed (403) and too many attempts is Too many attempts (429). This five-minute confirmation is separate from the 15-minute rule that guards changing how you sign in, described above.

Reference

ItemValue
Session lifetime7 days (cookie, HttpOnly, SameSite=Lax)
Re-authenticationpassword accounts: the current password, always; password-less accounts and provider linking: a session younger than 15 minutes. Password checks are limited to 5 a minute per account
Two-factor challenge5 minutes, single use
Two-factor lockoutfive wrong codes within 15 minutes lock two-factor sign-in until the 15 minutes end; each code works once
AuthenticatorRFC 6238 TOTP, six digits
Backup codes10, one-time, shown once; regenerate replaces all
PasskeysWebAuthn, user verification required, discoverable, ES256 / RS256; web only
Email verification24-hour link; skipped when the control plane sends no mail
Password8–256 characters, a number, a special character, no edge whitespace
Permanent-action confirmationorganization setting, off by default; password or authenticator code; unlocks for 5 minutes on that sign-in
Sessions revoked on2FA on/off, backup codes regenerated, passkey added/removed, provider linked/unlinked (all but the current); password reset (all)

Errors

Account routes answer with a short error string; the app shows the sentence in the table.

ErrorStatusMeaning
Invalid credentials401Wrong email or password — the same answer whether or not the account exists.
Verify your email before signing in…403The sign-up link has not been opened yet.
Reauthentication required403Type your current password (a password-less account: sign in again — the 15-minute window has passed).
reauth_required403The organization asks for confirmation before this permanent action. Prove it with POST /auth/reauth and repeat.
reauth_unavailable400POST /auth/reauth on an account with no password and no authenticator; sign in again instead.
incorrect_current_password400Change password: the current password is wrong. (400, not 403: the app treats a 403 as "ask again".)
password_unchanged400Change password: the new password equals the current one.
password_breached400The password appears in a known data breach. Choose another. Returned by sign-up, invitation sign-up, password reset and change password.
no_password409Change password on an account that signs in without a password.
Too many requests429Too many password checks for this account in a minute; wait and try again.
two_factor_enabled409Two-factor is already on; disable it before enrolling again.
Not enrolled, Invalid code400Verify was called without a pending enrollment, or the code did not match. A code that was already used also answers Invalid code.
Invalid or expired challenge400The 5-minute sign-in challenge is over, or it was already used to sign in; sign in again.
Too many attempts429Five wrong codes within 15 minutes; two-factor sign-in stays locked until the 15 minutes end. Signing in again does not reset it.
passkey_exists409That authenticator is already registered on the account.
Invalid credential400The browser's WebAuthn response did not verify (wrong origin, counter went backwards, no user verification).
Not found404The passkey is not on this account.
last_sign_in_method409Unlinking would leave no password, passkey or other provider.
oauth_state_invalidredirectSign-in expired or was started in another browser. Try again. — the 10-minute provider round trip took too long, was tampered with, or came back in a different browser from the one that started it. A sign-in in progress while the control plane was upgraded also fails this way once.
oauth_email_unverifiedredirectThe provider has not verified this email address, so it cannot be used to create an account. Verify it with the provider, or sign up with a password.
oauth_exchange_failedredirectCould not complete sign-in. Try again. — the provider refused the code exchange.
oauth_signup_disabledredirectNew accounts cannot be created this way. — no linked account and sign-up is closed.
account_conflictredirectThe provider identity belongs to another user.
account_disabledredirectThe account is disabled.
oauth_reauth_required, oauth_unauthenticatedredirectLinking needs a recent sign-in, or the session ended during the round trip.
Not configured503The control plane has no root secret or that provider is not set up.
Edit on GitHub

Last updated on

On this page