Skip to main content

Auth and Security

Security boundaries are enforced on the backend. The frontend can hide controls for usability, but hidden UI is never authorization.

Authentication

Auth routes live in server/app/routers/auth.py. Passwords are hashed with bcrypt. Login/signup return a token for API clients and set an httpOnly tome_token cookie for the web app.

The backend also supports:

  • Email verification.
  • Password reset tokens.
  • Logout with token-version revocation.
  • Discord OAuth when configured.

Frontend auth state lives in web/src/lib/auth.tsx.

Authorization Layers

LayerMeaningCode
Request authUser is signed in.require_auth in server/app/deps.py
Platform adminUser can access /api/admin/*.require_admin
Campaign memberUser belongs to the campaign.require_member
Campaign DMUser can perform DM-only actions.require_dm
AI accessUser can use AI features.require_ai_access

Platform admin is User.isAdmin. Campaign role is a Membership.role. AI access is separate: effective access is User.aiAccess OR User.isAdmin.

API Safety Rules

  • Validate every request body with Pydantic.
  • Scope every query by current user, campaign, or admin role.
  • Never return private storage paths directly.
  • Never serve admin core-rule files from public /uploads.
  • Use standard error helpers so clients get predictable envelopes.
  • Keep secrets in environment variables.

Public and Private Files

Public uploads are for user-visible images and are served from /uploads. Core-rule files live under private server/storage/ and are reachable only through admin download routes.

Rate Limits and Headers

Rate limiting helpers live in server/app/lib/rate_limit.py. Security headers are added by server/app/security_headers.py. Public invite preview and auth flows have additional hardening paths.