Skip to content

Backend-Mandatory Auth + Sync Local Flow

Date: 2026-04-15
Scope: exact implementation flow for backend-authenticated frontend sessions, refresh rotation, sync replay, and local testing.

1) Exact implementation flow

1.1 Login (frontend → backend)

  1. app/src/app/pages/LoginPage.tsx calls AuthContext.login(identifier, password).
  2. If VITE_BACKEND_URL is set, frontend uses backend auth mode (app/src/modules/auth/backendAuth.ts).
  3. Frontend sends POST /api/v1/auth/login with { email, password }.
    • If the user typed admin, chamador, relatorios, or cadastro, frontend normalizes to:
      • admin@neemias.local
      • chamador@neemias.local
      • relatorios@neemias.local
      • cadastro@neemias.local
  4. Backend verifies password (workers/src/modules/auth/password.ts) and creates auth session (workers/src/routes/auth.ts):
    • creates refresh token
    • stores hashed refresh token in auth_refresh_sessions
    • creates CSRF token
    • signs short-lived access token
  5. Backend returns:
    • accessToken
    • accessTokenExpiresAt
    • refreshToken (bearer mode) or httpOnly cookie (cookie mode)
    • csrfToken
    • user payload
  6. Frontend persists session metadata in IndexedDB sessions and user metadata in users (AuthContext.persistBackendSession()), then loads students from backend (fetchStudentsFromBackend).

1.2 Refresh-token rotation

  1. Frontend calls POST /api/v1/auth/refresh when needed (hydration/retry path).
  2. Backend validates refresh token hash in auth_refresh_sessions.
  3. Backend creates a new refresh/access pair and revokes old refresh session:
    • sets revoked_at, rotated_at, replaced_by
  4. Frontend replaces local session metadata with the new session artifacts.

1.3 Sync replay and auth bridge

  1. Offline queue drain (OfflineContext) calls syncQueueEntryWithBackend() for each pending item.
  2. Each request sends:
    • Authorization: Bearer <accessToken>
    • X-Device-Id
    • Idempotency-Key
    • X-CSRF-Token when available
  3. If backend returns 401:
    • frontend attempts refresh (AuthContext.refreshAccessToken())
    • if refresh fails, session is marked EXPIRED
    • queue entries remain pending/retrying (not force-synced)
  4. Conflict metadata from backend conflicts[] is written to local attendance events and surfaced in UI.

When backend is configured with AUTH_SESSION_MODE=cookie:

  • refresh token is stored in httpOnly cookie
  • mutating routes enforce CSRF via X-CSRF-Token
  • frontend includes credentials (credentials: "include") for auth/sync requests

2) Local setup (backend mandatory)

2.1 Backend (terminal 1)

bash
cd /home/runner/work/neemias/neemias
pnpm install

Start PostgreSQL locally (choose one):

  • Option A (recommended): Docker Compose stack
bash
cd /home/runner/work/neemias/neemias/infra/compose
cp .env.example .env
docker compose up -d db
  • Option B: run your own local Postgres and set DATABASE_URL accordingly.

Run migrations and seed demo backend users:

bash
cd /home/runner/work/neemias/neemias
pnpm --dir backend migrate
pnpm --dir backend seed:demo

Run backend:

bash
cd /home/runner/work/neemias/neemias
AUTH_MODE=dev AUTH_SESSION_MODE=bearer pnpm --dir backend dev

2.2 Frontend (terminal 2)

Create app env:

bash
cd /home/runner/work/neemias/neemias/app
cp .env.example .env

Run frontend:

bash
cd /home/runner/work/neemias/neemias
pnpm --dir app dev

2.3 Demo login credentials (backend seed)

  • admin / senha123
  • chamador / senha123
  • relatorios / senha123
  • cadastro / senha123

Equivalent backend emails:

  • admin@neemias.local
  • chamador@neemias.local
  • relatorios@neemias.local
  • cadastro@neemias.local

2.4 Connectivity checks (frontend must see backend)

  1. Backend health:
bash
curl http://localhost:3000/api/v1/health
  1. Browser DevTools in frontend:
    • login request should target http://localhost:3000/api/v1/auth/login
    • sync request should target http://localhost:3000/api/v1/sync/events
  2. If requests are missing:
    • verify app/.env has VITE_BACKEND_URL=http://localhost:3000
    • restart frontend dev server after editing .env

3) Known boundary

PII encryption-at-rest lifecycle is now implemented for session secrets and sensitive IndexedDB payload fields using browser-native crypto envelopes, in-memory key clear on logout/expiry, and re-auth-triggered key rotation.

Distributed under MIT License.