From 57d400c6dea503445e57254798d708f7d9ede42c Mon Sep 17 00:00:00 2001 From: Kyle Pope Date: Tue, 17 Mar 2026 23:25:27 +0800 Subject: [PATCH] Update .env.example and README.md for passkey authentication MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - .env.example: Add WEBAUTHN_RP_ID, WEBAUTHN_RP_NAME, WEBAUTHN_ORIGIN, ENVIRONMENT, and UMBRA_URL with documentation comments - README.md: Full rewrite — remove outdated PIN/bcrypt references, document current auth stack (Argon2id + TOTP + passkeys), all 17 API route groups, security features, and Docker deployment Co-Authored-By: Claude Opus 4.6 (1M context) --- backend/.env.example | 12 +++ backend/README.md | 221 ++++++++++++++----------------------------- 2 files changed, 85 insertions(+), 148 deletions(-) diff --git a/backend/.env.example b/backend/.env.example index 396bfaa..e90dbc3 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -1,2 +1,14 @@ DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/umbra SECRET_KEY=your-secret-key-change-in-production +ENVIRONMENT=development + +# Public-facing URL (used for ntfy click links, CORS derivation) +UMBRA_URL=http://localhost + +# WebAuthn / Passkey authentication +# RP_ID must be the eTLD+1 domain of the live site (e.g. umbra.ghost6.xyz) +# ORIGIN must include the scheme (https://) +# These defaults work for local development; override in production .env +WEBAUTHN_RP_ID=localhost +WEBAUTHN_RP_NAME=UMBRA +WEBAUTHN_ORIGIN=http://localhost diff --git a/backend/README.md b/backend/README.md index 99cce58..0f51c54 100644 --- a/backend/README.md +++ b/backend/README.md @@ -1,39 +1,37 @@ # UMBRA Backend -A complete FastAPI backend for the UMBRA application with async SQLAlchemy, PostgreSQL, authentication, and comprehensive CRUD operations. +FastAPI backend for the UMBRA life management application with async SQLAlchemy, PostgreSQL, multi-user RBAC, and comprehensive security. ## Features -- **FastAPI** with async/await support -- **SQLAlchemy 2.0** with async engine -- **PostgreSQL** with asyncpg driver -- **Alembic** for database migrations -- **bcrypt** for password hashing -- **itsdangerous** for session management -- **PIN-based authentication** with secure session cookies -- **Full CRUD operations** for all entities -- **Dashboard** with aggregated data -- **CORS enabled** for frontend integration +- **FastAPI** with async/await and Pydantic v2 +- **SQLAlchemy 2.0** async engine with `Mapped[]` types +- **PostgreSQL 16** via asyncpg +- **Alembic** database migrations (001-061) +- **Authentication**: Argon2id passwords + signed httpOnly cookies + optional TOTP MFA + passkey (WebAuthn/FIDO2) +- **Multi-user RBAC**: admin/standard roles, per-user resource scoping +- **Session management**: DB-backed sessions, sliding window expiry, concurrent session cap +- **Account security**: Account lockout (10 failures = 30-min lock), CSRF protection, rate limiting +- **APScheduler** for background notification dispatch ## Project Structure ``` backend/ -├── alembic/ # Database migrations -│ ├── versions/ # Migration files -│ ├── env.py # Alembic environment -│ └── script.py.mako # Migration template +├── alembic/versions/ # 61 database migrations ├── app/ -│ ├── models/ # SQLAlchemy models -│ ├── schemas/ # Pydantic schemas -│ ├── routers/ # API route handlers -│ ├── config.py # Configuration -│ ├── database.py # Database setup -│ └── main.py # FastAPI application -├── requirements.txt # Python dependencies -├── Dockerfile # Docker configuration -├── alembic.ini # Alembic configuration -└── start.sh # Startup script +│ ├── models/ # 21 SQLAlchemy 2.0 models +│ ├── schemas/ # 14 Pydantic v2 schema modules +│ ├── routers/ # 17 API routers +│ ├── services/ # Auth, session, passkey, TOTP, audit, recurrence, etc. +│ ├── jobs/ # APScheduler notification dispatch +│ ├── config.py # Pydantic Settings (env vars) +│ ├── database.py # Async engine + session factory +│ └── main.py # FastAPI app + CSRF middleware +├── requirements.txt +├── Dockerfile +├── alembic.ini +└── start.sh ``` ## Setup @@ -41,160 +39,87 @@ backend/ ### 1. Install Dependencies ```bash -cd backend pip install -r requirements.txt ``` ### 2. Configure Environment -Create a `.env` file: +Copy `.env.example` to `.env` and configure: ```bash -DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/umbra -SECRET_KEY=your-secret-key-change-in-production +DATABASE_URL=postgresql+asyncpg://postgres:postgres@db:5432/umbra +SECRET_KEY=generate-a-strong-random-key +ENVIRONMENT=production + +# WebAuthn / Passkeys (required for passkey auth) +WEBAUTHN_RP_ID=your-domain.com +WEBAUTHN_RP_NAME=UMBRA +WEBAUTHN_ORIGIN=https://your-domain.com ``` -### 3. Create Database - -```bash -createdb umbra -``` - -### 4. Run Migrations +### 3. Run Migrations ```bash alembic upgrade head ``` -### 5. Start Server +### 4. Start Server ```bash -# Using the start script -chmod +x start.sh -./start.sh - -# Or directly with uvicorn -uvicorn app.main:app --reload +uvicorn app.main:app --host 0.0.0.0 --port 8000 ``` -The API will be available at `http://localhost:8000` +## API Routes -## API Documentation +All routes require authentication (signed session cookie) except `/api/auth/*` and `/health`. -Interactive API documentation is available at: -- **Swagger UI**: http://localhost:8000/docs -- **ReDoc**: http://localhost:8000/redoc +| Prefix | Description | +|--------|-------------| +| `/api/auth` | Login, logout, register, setup, status, password, TOTP, passkeys | +| `/api/admin` | User management, system config, audit logs (admin only) | +| `/api/todos` | Task management with categories and priorities | +| `/api/events` | Calendar events with recurrence support | +| `/api/event-invitations` | Event invitation RSVP and management | +| `/api/event-templates` | Reusable event templates | +| `/api/calendars` | Calendar CRUD | +| `/api/shared-calendars` | Calendar sharing with permission levels | +| `/api/reminders` | Reminder management with snooze | +| `/api/projects` | Projects with tasks, comments, and collaboration | +| `/api/people` | Contact management | +| `/api/locations` | Location management | +| `/api/connections` | User connections (friend requests) | +| `/api/notifications` | In-app notification centre | +| `/api/settings` | User preferences and ntfy configuration | +| `/api/dashboard` | Aggregated dashboard data | +| `/api/weather` | Weather widget data | -## API Endpoints +## Authentication -### Authentication -- `POST /api/auth/setup` - Initial PIN setup -- `POST /api/auth/login` - Login with PIN -- `POST /api/auth/logout` - Logout -- `GET /api/auth/status` - Check auth status +UMBRA supports three authentication methods: -### Todos -- `GET /api/todos` - List todos (with filters) -- `POST /api/todos` - Create todo -- `GET /api/todos/{id}` - Get todo -- `PUT /api/todos/{id}` - Update todo -- `DELETE /api/todos/{id}` - Delete todo -- `PATCH /api/todos/{id}/toggle` - Toggle completion +1. **Password** (Argon2id) - Primary login method +2. **TOTP MFA** - Optional second factor via authenticator apps +3. **Passkeys** (WebAuthn/FIDO2) - Optional passwordless login via biometrics, security keys, or password managers -### Calendar Events -- `GET /api/events` - List events (with date range) -- `POST /api/events` - Create event -- `GET /api/events/{id}` - Get event -- `PUT /api/events/{id}` - Update event -- `DELETE /api/events/{id}` - Delete event +Passkey login bypasses TOTP (a passkey is inherently two-factor: possession + biometric/PIN). -### Reminders -- `GET /api/reminders` - List reminders (with filters) -- `POST /api/reminders` - Create reminder -- `GET /api/reminders/{id}` - Get reminder -- `PUT /api/reminders/{id}` - Update reminder -- `DELETE /api/reminders/{id}` - Delete reminder -- `PATCH /api/reminders/{id}/dismiss` - Dismiss reminder +## Security -### Projects -- `GET /api/projects` - List projects -- `POST /api/projects` - Create project -- `GET /api/projects/{id}` - Get project -- `PUT /api/projects/{id}` - Update project -- `DELETE /api/projects/{id}` - Delete project -- `GET /api/projects/{id}/tasks` - List project tasks -- `POST /api/projects/{id}/tasks` - Create project task -- `PUT /api/projects/{id}/tasks/{task_id}` - Update task -- `DELETE /api/projects/{id}/tasks/{task_id}` - Delete task - -### People -- `GET /api/people` - List people (with search) -- `POST /api/people` - Create person -- `GET /api/people/{id}` - Get person -- `PUT /api/people/{id}` - Update person -- `DELETE /api/people/{id}` - Delete person - -### Locations -- `GET /api/locations` - List locations (with category filter) -- `POST /api/locations` - Create location -- `GET /api/locations/{id}` - Get location -- `PUT /api/locations/{id}` - Update location -- `DELETE /api/locations/{id}` - Delete location - -### Settings -- `GET /api/settings` - Get settings -- `PUT /api/settings` - Update settings -- `PUT /api/settings/pin` - Change PIN - -### Dashboard -- `GET /api/dashboard` - Get dashboard data -- `GET /api/upcoming?days=7` - Get upcoming items - -## Database Schema - -The application uses the following tables: -- `settings` - Application settings and PIN -- `todos` - Task items -- `calendar_events` - Calendar events -- `reminders` - Reminders -- `projects` - Projects -- `project_tasks` - Tasks within projects -- `people` - Contacts/people -- `locations` - Physical locations +- CSRF protection via `X-Requested-With` header middleware +- All Pydantic schemas use `extra="forbid"` (mass-assignment prevention) +- Nginx rate limiting on auth, registration, and admin endpoints +- DB-backed account lockout after 10 failed attempts +- Timing-safe dummy hash for non-existent users (prevents enumeration) +- SSRF validation on ntfy webhook URLs +- Naive datetimes throughout (Docker runs UTC) ## Docker -Build and run with Docker: +The backend runs as non-root `appuser` in `python:3.12-slim`: ```bash docker build -t umbra-backend . -docker run -p 8000:8000 -e DATABASE_URL=... -e SECRET_KEY=... umbra-backend +docker run -p 8000:8000 --env-file .env umbra-backend ``` -## Development - -### Create New Migration - -```bash -alembic revision --autogenerate -m "Description of changes" -``` - -### Apply Migrations - -```bash -alembic upgrade head -``` - -### Rollback Migration - -```bash -alembic downgrade -1 -``` - -## Security Notes - -- Change `SECRET_KEY` in production -- Use strong PINs (minimum 4 digits recommended) -- Session cookies are httpOnly and last 30 days -- All API endpoints (except auth) require authentication -- PINs are hashed with bcrypt before storage +In production, use Docker Compose (see root `docker-compose.yaml`).