The middleware gate is presence-only — it runs on the Edge runtime and can't
reach the database, so any non-empty `ftstore_session` cookie got past it.
Nine handlers relied on that alone and answered without `withAuth()`:
`/api/dashboard/*`, `/api/metrics/overview`, `/api/queue/{retry,batch}`,
`/api/entitlements` and `/api/privacy-cache`.
Wrap them. The only routes that stay open are the deliberately public ones:
`/api/auth/*`, `/api/health`, `/api/branding`, and the UA-gated
`/api/ftstore-{app,manager}/*` self-update proxies.
3.6 KiB
Authentication
FTStore Admin uses a session-based authentication system with user approval flow.
How It Works
- Sessions: HTTP-only cookies (
ftstore_session) with 30-day expiry - Passwords: Hashed with scrypt (Node.js
cryptomodule, no external dependencies) - Middleware: Cookie-presence check on all routes (Edge-compatible, no DB calls)
- Route protection: API routes wrapped with
withAuth()/withAdmin()for DB-level auth
The middleware check is presence-only — it runs on the Edge runtime and cannot reach the database, so any non-empty
ftstore_sessionvalue gets past it.withAuth()is what actually validates the session, which is why every non-public API route has to be wrapped. The only handlers that may stay unwrapped are the deliberately public ones:/api/auth/*,/api/health,/api/branding, and the User-Agent-gated/api/ftstore-app/*and/api/ftstore-manager/*self-update proxies.This matters beyond the browser: FTStore Manager ships an on-device console that talks to these same routes, and its whole security model is that the app carries no credential — so a route that answers without a valid session is a hole in that model too.
First-User Setup
- Navigate to the application — you'll be redirected to
/login - Click "Register" to create the first account
- The first user is automatically an admin and approved
- All subsequent users require admin approval before they can log in
User Approval Flow
- New user registers at
/register - They see a "pending approval" message
- An admin goes to Settings > Users tab
- Admin clicks the checkmark to approve the user
- The user can now log in
User Roles
| Role | Permissions |
|---|---|
admin |
Full access + user management (approve, role change, delete) |
user |
Access to all dashboard features |
Settings > Users Tab
Admins see a "Users" tab in Settings with:
- User list with role/status badges
- Approve/reject buttons
- Role toggle (admin/user)
- Delete user (with confirmation dialog)
Admins cannot demote themselves or delete their own account.
CLI User Management
For Docker deployments, manage users via CLI:
# Create a user
docker exec -it <container> npx tsx scripts/manage-users.ts create <username> <password>
# Create an admin user
docker exec -it <container> npx tsx scripts/manage-users.ts create <username> <password> --admin
# List all users
docker exec -it <container> npx tsx scripts/manage-users.ts list
# Approve a pending user
docker exec -it <container> npx tsx scripts/manage-users.ts approve <username>
# Change user role
docker exec -it <container> npx tsx scripts/manage-users.ts set-role <username> admin
# Reset password
docker exec -it <container> npx tsx scripts/manage-users.ts reset-password <username> <new-password>
# Delete a user
docker exec -it <container> npx tsx scripts/manage-users.ts delete <username>
API Endpoints
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/auth/register |
Public | Register new user |
| POST | /api/auth/login |
Public | Login |
| POST | /api/auth/logout |
Public | Logout (clears session) |
| GET | /api/auth/me |
Session | Current user info |
| GET | /api/users |
Admin | List users |
| PUT | /api/users |
Admin | Update user (approve, role) |
| DELETE | /api/users?id=N |
Admin | Delete user |
Session Cleanup
Expired sessions are automatically cleaned up when the cleanup action runs (Settings > Admin Actions > Run Cleanup, or via the worker's scheduled cleanup).