Skip to content

Authorization

[!abstract] Summary All data is scoped to groups. Users have roles that control access to features. Registration requires email confirmation and admin approval.

Multi-Tenancy Model

Every user belongs to exactly one group. All data entities are scoped to groups (see Entity Relationship Diagram for the full schema). Users in the same group can see each other's markers, transactions, and budget accounts. Notes can be private (user-only) or public (group-visible).

Roles

Role Description
User Default role, standard access to group data
Admin Full access + user management + Hangfire dashboard

Admin Assignment

Admins are configured via Security__AdminUserNames environment variable (comma-separated usernames). On application startup:

  1. Users in the list who aren't admins are promoted to Admin
  2. Users not in the list who are admins are demoted to User

Admins cannot be assigned via UI.

Admin Capabilities

  • Approve, decline, or deactivate users
  • Access all admin endpoints (/api/users/*)
  • Access Hangfire dashboard (/hangfire)
  • All standard User capabilities

Feature Modules

Groups can have specific modules enabled/disabled:

Module Features
Map Markers, photos, map view
Budget Transactions, categories, budget accounts, recurring transactions
Notes Checklists, items, sharing

Module access is checked via hasModule() in frontend and enforced in backend.

Registration Flow

New users go through a two-step verification:

stateDiagram-v2
    [*] --> EmailUnconfirmed: Register
    EmailUnconfirmed --> Pending: Confirm email
    Pending --> Confirmed: Admin approves
    Pending --> Declined: Admin declines
    Confirmed --> Deactivated: Admin deactivates
    Deactivated --> Confirmed: Admin reactivates

Email Status

Status Description
Unconfirmed Initial state after registration
Confirmed Email verified via confirmation link
ChangePending User requested email change, awaiting confirmation

Users can resend confirmation emails (with cooldown). Unconfirmed registrations:

  • Receive warning email before expiry
  • Are automatically declined after expiry period

Registration Status

Status Description
Pending Email confirmed, awaiting admin approval
Confirmed Admin approved, full access granted
Declined Admin declined (with reason)
Deactivated Admin deactivated existing user

Admin Status Changes

Transition Requirements
Pending → Confirmed Email must be confirmed, GroupId must be provided
Pending → Declined Decline reason required
Confirmed → Deactivated Cannot deactivate admin users
Deactivated → Confirmed Can optionally re-enable recurring transactions

Admins cannot change their own status.

Decline Reasons

Reason Description
UnknownPerson Don't know this person
DuplicateAccount Already has an account
SpamBot Detected as spam/bot
EmailNotConfirmed Auto-set when registration expires
Other Custom reason (requires text)

Route Guards (Frontend)

Two route guards in components/routing/:

Component Purpose
ProtectedRoute Requires authentication; redirects to login if not logged in
GuestRoute Redirects to home if already logged in (for login, register, etc.)

ProtectedRoute optional props:

Prop Purpose
requiredModule Require specific module access (e.g., MODULE_TYPES.MAP)
requiredRole Require specific role (e.g., ROLES.ADMIN)
<Route path={ROUTES.LOGIN} element={<GuestRoute><Login /></GuestRoute>} />
<Route path={ROUTES.HOME} element={<ProtectedRoute><Hub /></ProtectedRoute>} />
<Route path={ROUTES.MAP} element={<ProtectedRoute requiredModule={MODULE_TYPES.MAP}><Map /></ProtectedRoute>} />
<Route path={ROUTES.ADMIN} element={<ProtectedRoute requiredRole={ROLES.ADMIN}><Admin /></ProtectedRoute>} />

Registration status-specific routes:

  • /registration-pending — Shown to pending users
  • /registration-declined — Shown to declined users
  • /account-deactivated — Shown to deactivated users