TurboPanel Docs
Database

Identity

Who a person is to the control plane: the Better Auth-compatible user, credential, session and verification tables.

Tables on this page: 2fa · account · passkey · session · user · verification. Generated from migration 0004_schema_comments; see How to read this.

2fa

TOTP enrolment for a user, at most one row per user (uniq_2fa_user_id); inserted or reset on enable, verified once, and deleted when two-factor is disabled.

ColumnTypeNullDefaultDescription
id (PK)uuidnouuidv7()Primary key (uuidv7(), time-ordered).
created_attimestamp(3) with time zonenonow()Row creation time.
updated_attimestamp(3) with time zonenonow()Last write time; the ORM sets it to now() on every update.
user_iduuidnoFK → user.id (on delete cascade). Enrolled user; unique, so re-enabling resets the existing row instead of adding one, and disable deletes it.
secrettextnoTOTP shared secret sealed as a tpsecret envelope with the data-encryption key; never plaintext and never returned after enrolment.
is_verifiedbooleannofalseFalse until the user proves the first six-digit code; only a verified row turns on user.is_2fa_enabled and receives backup codes.
backup_codestextnoJSON array of HMAC verifier envelopes (tpotp.vN.hex) for the ten one-time backup codes, [] until verified; a used code is removed from the array.

Constraints and indexes

  • Unique uniq_2fa_user_id: (user_id)
  • Index idx_2fa_user_id: (user_id)

account

One sign-in credential per user and provider: the local password account (credential) or a linked GitHub/Google identity; unique on provider plus subject.

ColumnTypeNullDefaultDescription
id (PK)uuidnouuidv7()Primary key (uuidv7(), time-ordered).
created_attimestamp(3) with time zonenonow()Row creation time.
updated_attimestamp(3) with time zonenonow()Last write time; the ORM sets it to now() on every update.
user_iduuidnoFK → user.id (on delete cascade).
provider_idtextnocredential for the local password account, or the OAuth provider id github or google for a linked identity.
provider_user_idtextnoProvider-side subject: the user's own uuid on credential rows, else the GitHub/Google account id; unique together with provider_id.
access_tokentextyesReserved OAuth column; the provider flow deliberately writes null and never persists provider tokens.
refresh_tokentextyesReserved OAuth column; the provider flow deliberately writes null and never persists provider tokens.
id_tokentextyesReserved OAuth column; the provider flow deliberately writes null and never persists provider tokens.
access_token_expires_attimestamp(3) with time zoneyesReserved OAuth column; never written by any first-party code path.
refresh_token_expires_attimestamp(3) with time zoneyesReserved OAuth column; never written by any first-party code path.
scopetextyesReserved OAuth column; never written by any first-party code path.
passwordtextyesArgon2id PHC-format hash ($argon2id$v=19$m=N,t=N,p=N$salt$digest) on credential rows, set at sign-up, install and password reset; null on OAuth rows.

Constraints and indexes

  • Unique uniq_account_provider_user: (provider_id, provider_user_id)
  • Index idx_account_user_id: (user_id)

passkey

One WebAuthn credential registered by a user (several per user allowed), unique by credential_id; inserted at registration, updated on each passkey sign-in.

ColumnTypeNullDefaultDescription
id (PK)uuidnouuidv7()Primary key (uuidv7(), time-ordered).
created_attimestamp(3) with time zonenonow()Row creation time.
user_iduuidnoFK → user.id (on delete cascade).
aaguidtextyesAuthenticator model AAGUID decoded from the attestation as a dashed lowercase UUID string; identifies the make, not the individual key.
nametextyesUser-chosen label given at registration (the device or authenticator it lives on); shown in the Security screen, never used for matching.
public_keytextnoCredential public key as a JSON-serialised JWK (ES256 or RS256) converted from the attestation's COSE key; verifies sign-in assertions.
credential_idtextnoBase64url credential id from the attestation; unique across the instance and the lookup key for passkey sign-in.
counterbigintno0Authenticator signature counter from the last accepted assertion; a lower value rejects the sign-in (clone detection) and updates are compare-and-swap.
device_typevarchar(32)nomultiDevice when the attestation flags the credential backup-eligible, else singleDevice; derived once at registration.
is_backed_upbooleannoBackup-state flag from the attestation (credential synced by its provider); with device_type it drives the Synced / Multi-device / This device label.
transportstextyesJSON array string of WebAuthn transports reported at registration (for example internal, usb, hybrid), or null when none were reported.

Constraints and indexes

  • Unique uniq_passkey_credential_id: (credential_id)
  • Index idx_passkey_user_id: (user_id)

session

One row per signed-in session keyed by the opaque cookie token; rows are deleted (never extended) on sign-out or security changes and ignored once expired.

ColumnTypeNullDefaultDescription
id (PK)uuidnouuidv7()Primary key (uuidv7(), time-ordered).
created_attimestamp(3) with time zonenonow()Row creation time.
updated_attimestamp(3) with time zonenonow()Last write time; the ORM sets it to now() on every update.
user_iduuidnoFK → user.id (on delete cascade).
expires_attimestamp(3) with time zonenoFixed at creation to now + 7 days (SESSION_EXPIRES_IN_MS); never extended, and lookups treat rows past it as absent.
tokentextnoOpaque server-generated value, 32 random bytes base64url-encoded; unique, carried by the session cookie and matched verbatim.
ip_addressvarchar(45)yesClient address captured at sign-in as IPv4 or IPv6 text (hence 45 chars); informational only, null when unknown.
user_agenttextyesBrowser UA request header captured at sign-in; informational only, null when unknown.

Constraints and indexes

  • Unique session_token_unique: (token)
  • Index idx_session_user_id: (user_id)

user

One row per person who can sign in to the instance, keyed by unique email; created by password sign-up, OTP sign-in, OAuth sign-up or the install wizard.

ColumnTypeNullDefaultDescription
id (PK)uuidnouuidv7()Primary key (uuidv7(), time-ordered).
created_attimestamp(3) with time zonenonow()Row creation time.
updated_attimestamp(3) with time zonenonow()Last write time; the ORM sets it to now() on every update.
metadatajsonbyesReserved pairing jsonb with no first-party reader or writer today; stays null.
optionsjsonbyesReserved pairing jsonb with no first-party reader or writer today; stays null.
namevarchar(255)yesOptional display name copied at creation from the OAuth profile or the OTP sign-in form (1-255 chars); absent on password sign-up and never edited later.
emailvarchar(255)noUnique sign-in address, trimmed at write; the identity that accounts, sessions, OTP flows and invitation accepts are matched against.
is_email_verifiedbooleannofalseTrue once the address is proven: set at creation by OTP or OAuth sign-up and the install wizard, or later by the verify-email link and OTP routes.
is_2fa_enabledbooleannofalseDerived flag kept in step with the 2fa row: set true when TOTP enrolment is verified and false when two-factor is disabled.
is_disabledbooleannofalseSign-in gate read by every authn path (password, OTP, passkey, OAuth) and refused with account_disabled; no control-plane route writes it today.
roletextno'user'Instance role user, admin or superadmin; sign-ups get user, the install wizard mints the one superadmin, and admins bypass org grants.

Constraints and indexes

  • Unique user_email_unique: (email)
  • Check user_name_format_check: (name IS NULL) OR ((char_length((name)::text) >= 1) AND (char_length((name)::text) <= 255))
  • Check user_role_check: role IN ('user', 'admin', 'superadmin')

verification

Short-lived email verification tokens and OTP verifiers keyed by unique identifier; rows are upserted per purpose and deleted or left to expire on use.

ColumnTypeNullDefaultDescription
id (PK)uuidnouuidv7()Primary key (uuidv7(), time-ordered).
created_attimestamp(3) with time zonenonow()Row creation time.
updated_attimestamp(3) with time zonenonow()Last write time; the ORM sets it to now() on every update.
expires_attimestamp(3) with time zonenoHard expiry compared at read: 24 h for verify-email links, 300 s for OTPs and their attempt counters; expired rows are ignored and replaced.
identifiervarchar(255)noLookup key: the bare email for verify-email links, otp:TYPE:sha256(email) for an OTP and otp-attempts:TYPE:sha256(email) for its attempt counter.
valuetextnoNever the raw secret: SHA-256 hex of the link token, a keyed HMAC envelope tpotp.vN.hex for an OTP, or the decimal failed-attempt count.

Constraints and indexes

  • Unique verification_identifier_unique: (identifier)
Edit on GitHub

Last updated on

On this page