Skip to content

Authentication ​

core issues its own HS256 JWTs against local, Argon2id-hashed password accounts by default. OIDC to an external provider is optional and all-or-nothing — see Architecture: Authentication. See the API overview for the two auth carriers (bearer vs. cookie) and CSRF rules.

Endpoints (tags: Authentication, Account security, Me) ​

MethodPathPurpose
POST/v1/auth/registerRedeem an invite (joins the inviter's household with the invited role) or, when an admin has opened registration, join the install's household as a member. Never creates a household. 201 with the same body as login; 429 account-locked is possible.
POST/v1/auth/loginEmail + password sign-in. Failed attempts are throttled, see below.
POST/v1/auth/login/totpComplete sign-in when TOTP is enabled.
POST/v1/auth/refreshRotate a refresh token (single-use).
POST/v1/auth/logoutRevoke the current session.
GET/v1/auth/providersList configured sign-in methods (local, OIDC if enabled), the OIDC display name and registrationOpen.
GET/v1/auth/invites/{token}Look up a pending household invite.
POST/v1/auth/passwordChange your password (current password required; your other sessions are signed out).
POST/v1/auth/password/reset-requestADMIN only: mint a one-hour single-use reset link for a member, to hand over out of band. No email is sent.
POST/v1/auth/password/resetPublic: redeem the link with a new password. The token is the whole authorisation.
POST/v1/auth/totp/setupStart TOTP enrolment (current password required); returns the secret without enabling it.
POST/v1/auth/totp/confirmEnable TOTP with one live code; returns ten recovery codes.
POST/v1/auth/totp/disableRemove TOTP (password and a current code required).
DELETE/v1/auth/totpSame as /totp/disable, for clients that keep DELETE bodies.
GET/v1/auth/meThe caller's own account.
GET/v1/auth/startPublic OIDC sign-in entry: 302 to the authorisation endpoint, 404 when SSO is off.
PUT/v1/meUpdate your profile.
GET/PUT/v1/me/preferencesRead / patch timezone, locale, onboarding flag and region.
GET/v1/me/security-eventsYour own recent sign-in and security activity.
DELETE/v1/me, POST /v1/me/deleteDelete your own account behind a step-up body (password, plus code when TOTP is on). 403 step-up-required on a wrong factor; 409 for the household's last administrator. Soft delete with a seven-day restore window.

Full request/response schemas are in openapi/trove-core.yaml.

First login on a fresh install ​

Registration is closed by default (TROVE_REGISTRATION_OPEN=false). The first household and its admin are created once, automatically, on a boot where no users exist yet, from TROVE_ADMIN_EMAIL / TROVE_ADMIN_PASSWORD / TROVE_HOUSEHOLD_NAME / TROVE_ADMIN_COUNTRY (CA or US, default CA; it also sets the admin's currency, and neither can change later) — see finance.trove.app.bootstrap.FirstRunBootstrap. After that, the admin invites other members from the app; there is no open sign-up. TROVE_HOUSEHOLD_NAME (default Household) only names the household. These variables are read from core's environment; a Docker Compose install passes core only the variables listed in deploy/.env.example, so one that is not listed there keeps its default (see Environment variables). The bootstrap is one transaction. If TROVE_ADMIN_PASSWORD fails the password policy, nothing is created: the boot logs why and carries on, /v1/status still answers, and the next boot retries once you have fixed the value. An install first booted before this was fixed may have an administrator with no password; sign-in cannot work for it, so run docker compose run --rm trove-core --trove.cli.command="reset-password <email>" from deploy/ and open the link it prints. TROVE_REGISTRATION_OPEN only seeds the first boot. After that an administrator opens or closes registration in Settings (PUT /v1/admin/settings), and the choice is stored on the household.

Household administration (tag: Administration) ​

Every route here needs the ADMIN role and acts only on the caller's own household; a member of another household is 404.

MethodPathPurpose
GET/v1/admin/usersList the household's members, inactive ones included.
DELETE/v1/admin/users/{id}Remove a member (soft delete, seven-day restore window).
POST/v1/admin/users/{id}/restoreBring a removed member back inside the window.
PUT/v1/admin/users/{id}/roleMake a member an ADMIN, or a MEMBER again.
POST/v1/admin/users/{id}/unlockEnd every sign-in throttle on a member's account (not your own).
DELETE/v1/admin/users/{id}/totpRemove a member's second factor, e.g. a lost phone (not your own; use DELETE /v1/auth/totp for that).
GET/POST/v1/admin/invitesList or create invite links. The link (token and url) is returned on creation (201) and again by the list for as long as the invite is still usable; both are null once it is accepted, revoked or expired.
DELETE/v1/admin/invites/{id}Withdraw an unredeemed invite.
GET/PUT/v1/admin/settingsOpen registration, scheduled bank sync.
GET/v1/auditPaged audit log of mutating requests (ADMIN only; kept 365 days).

The household always keeps at least one active administrator. Removing or demoting the last one is 409, so the last administrator who wants to leave first makes another member an administrator with PUT /v1/admin/users/{id}/role. A demotion signs the member out everywhere, so the old role cannot outlive the decision in a live token; a promotion reaches the member's token at its next refresh.

Sessions and step-up ​

  • The access token lives 15 minutes. A refresh token lasts 24 hours, or 12 hours idle, and is single-use with a 30 second reuse grace, so two tabs racing a refresh are not treated as theft. Real reuse is detected and logged.
  • After a password login for a TOTP account, the challenge is valid for 60 seconds. TOTP is six digits, 30 second period, with ten recovery codes. A recovery code is matched without regard to case, spaces or the hyphen in the middle.
  • Data export and account deletion need a step-up body: password, plus code where TOTP is on. Each request must carry its own step-up factor; nothing is remembered between requests. A missing or wrong factor is 403 step-up-required. TOTP setup needs the password; TOTP disable needs the password and a current code.
  • Passwords are 12 to 128 characters.

Sign-in throttling ​

Five failed sign-ins for an account from one address start a backoff of 30 seconds that doubles per further failure, up to 15 minutes. An account that collects 100 failures in an hour also refuses addresses it has never signed in from. These refusals look like a wrong password (401 credentials-invalid) on purpose. Separately, one address with 20 failures in 10 minutes (or no resolvable address) gets 429 account-locked with Retry-After; this applies to login, login/totp and register. A wrong TOTP code counts as a failure. An admin can end the account-level throttles with POST /v1/admin/users/{id}/unlock; the per-address 429 clears itself after the Retry-After wait.

Released under the AGPL-3.0-or-later License.