Skip to content

feat: add optional authentication with login, registration, and admin dashboard#336

Merged
pancacake merged 2 commits into
HKUDS:multi-userfrom
xor-xe:feature/auth-multiuser
Apr 18, 2026
Merged

feat: add optional authentication with login, registration, and admin dashboard#336
pancacake merged 2 commits into
HKUDS:multi-userfrom
xor-xe:feature/auth-multiuser

Conversation

@xor-xe

@xor-xe xor-xe commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Continuation of #252, re-targeted to multi-user and aligned to v1.1.0.

Implements optional authentication for public deployments. Auth is disabled by default (AUTH_ENABLED=false), so all existing localhost users are completely unaffected.

Auth (simple, no PocketBase)

  • bcrypt + JWT sessions, file-based user store, require_auth / require_admin FastAPI dependencies
  • Login/register pages, admin dashboard, logout button, route protection middleware

PocketBase sidecar (optional)

  • Activated only when POCKETBASE_URL is set — falls back to SQLite/JSON otherwise
  • SessionStoreProtocol + PocketBaseSessionStore with JSONL write-ahead buffer
  • Email-based auth, token introspection with 60s cache, Docker Compose integration

Setup

  1. Set AUTH_ENABLED=true + NEXT_PUBLIC_AUTH_ENABLED=true
  2. Navigate to /register — first user becomes admin
  3. Optionally run PocketBase sidecar for scalable multi-user storage

xor-xe added 2 commits April 17, 2026 21:40
Closes HKUDS#227. Auth is disabled by default (AUTH_ENABLED=false) so
localhost usage is unaffected. Set AUTH_ENABLED=true +
NEXT_PUBLIC_AUTH_ENABLED=true to require login when hosting publicly.

Backend
- New deeptutor/services/auth.py: bcrypt password hashing, JWT
  create/decode, multi-user JSON store with role + created_at schema,
  auto-migration of old flat-hash format, first-user → admin bootstrap
- New deeptutor/api/routers/auth.py: require_auth / require_admin
  FastAPI dependencies; public endpoints /login /logout /status
  /register /is_first_user; admin-only /users /users/{u}/role
- deeptutor/api/main.py: Depends(require_auth) applied to all 14
  protected routers
- deeptutor/api/routers/unified_ws.py: cookie-based JWT check before
  ws.accept() when AUTH_ENABLED
- Added bcrypt>=4.0.0 and python-jose[cryptography]>=3.3.0 to
  requirements/server.txt and pyproject.toml extras

Frontend
- web/middleware.ts: route protection; /login and /register are public
- web/lib/api.ts: apiFetch wrapper — credentials:include + 401→login
- web/lib/auth.ts: login/logout/fetchAuthStatus + register() +
  checkIsFirstUser()
- web/lib/admin-api.ts: listUsers / deleteUser / setUserRole
- web/lib/session-api.ts: credentials:include on all fetches;
  expectJson redirects to /login on 401 instead of throwing
- web/app/(auth)/login/page.tsx: auto-redirects to /register when no
  users exist; shows success banner after registration
- web/app/(auth)/register/page.tsx: new registration page with
  first-user admin notice and password confirmation
- web/app/(admin)/admin/users/page.tsx: admin dashboard — user table
  with role toggle and delete; guards against self-demotion/deletion
- AdminLink and LogoutButton hidden when AUTH_ENABLED=false
- .env.example and README.md updated with auth vars and setup guide

Made-with: Cursor
Introduces PocketBase as an optional sidecar for authentication and
session/KB storage, activated only when POCKETBASE_URL is set in .env.
Falls back to the existing SQLite/JSON backend when not configured.

Backend:
- SessionStoreProtocol (typing.Protocol) + get_session_store() factory
- PocketBaseSessionStore: JSONL write-ahead buffer, batch-flush on turn end
- pocketbase_client.py: singleton admin client, 60s in-memory token cache
- auth.py: additive PocketBase path (email-based login/register)
- CORS: explicit origins instead of wildcard (wildcard+credentials fails)
- WebSocket: validate token at connect time when AUTH_ENABLED

Infrastructure:
- docker-compose: pocketbase service with healthcheck + depends_on
- scripts/pb_setup.py: idempotent PocketBase collection bootstrap
- requirements/server.txt: pocketbase>=0.12.0

Frontend:
- Register/login: username field -> email field for PocketBase mode
- auth.ts: normalise FastAPI 422 errors to plain strings
- agents page: guard bots.map() against non-array responses
- settings page: graceful fetch error handling
- *.env.local added to .gitignore

Docs: README PocketBase sidecar setup section added
@pancacake

Copy link
Copy Markdown
Collaborator

Thank you!!!!

@pancacake

Copy link
Copy Markdown
Collaborator

I'll take a look at it very soon

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants