Files
NixReaperandClaude Sonnet 5 7bee596a0e
CI / lint (push) Canceled after 0s
CI / typecheck (push) Canceled after 0s
CI / unit-tests (push) Canceled after 0s
CI / integration-tests (push) Canceled after 0s
CI / container-build (push) Canceled after 0s
CI / dependency-audit (push) Canceled after 0s
Add user accounts: registration, login, and JWT auth
The first authenticated-user concept in Aurora Core -- everything else in
this codebase is public, read-only catalog data. Foundation for ratings
and a watchlist (not yet built): POST /auth/register, POST /auth/login,
GET /auth/me.

Security specifics worth knowing:
- Passwords hashed with argon2 (via argon2-cffi), never stored plain or
  logged.
- Login returns an identical 401 for a nonexistent email and a wrong
  password on a real one, including matching response timing
  (burn_time_like_a_password_check) -- otherwise either the status code
  or the timing alone lets a client enumerate registered emails.
- AURORA_SECRET_KEY now actually signs JWTs (previously defined but
  unused anywhere) -- .env.example's existing token_urlsafe(48) guidance
  already produces a long enough key, just flagged its new stakes.
- Email matched case-insensitively via explicit normalization in the
  service layer, not relied on from Pydantic's EmailStr (which does not
  lowercase the local part).

12 new integration tests (register/login/me over real HTTP via the
`client` fixture) plus 10 unit tests for the hashing/JWT logic itself,
following the same-day lesson that only unit tests actually execute
locally without Postgres -- the auth core is tested for real here rather
than only through integration tests that might not run before a deploy.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-09-06 06:15:39 -05:00

65 lines
2.2 KiB
Bash

# Copy to .env and fill in real values for local development.
# NEVER commit a real .env file.
# --- Runtime ---
AURORA_ENV=development
AURORA_LOG_LEVEL=INFO
AURORA_API_DOCS_ENABLED=true
# --- Database ---
# Async URL used by the application (asyncpg driver).
DATABASE_URL=postgresql+asyncpg://aurora:aurora@localhost:5432/aurora_core
# Sync URL used by Alembic migrations (psycopg2 driver).
DATABASE_URL_SYNC=postgresql+psycopg2://aurora:aurora@localhost:5432/aurora_core
DATABASE_POOL_SIZE=10
DATABASE_MAX_OVERFLOW=20
# --- Redis ---
REDIS_URL=redis://localhost:6379/0
# If false, the app runs without caching/rate-limiting when Redis is unreachable
# instead of failing readiness checks.
REDIS_REQUIRED=false
# --- Security ---
# Signs user-account JWT access tokens (app/core/auth.py) -- a weak or
# leaked value lets anyone forge a valid login for any user id. Generate
# with: python -c "import secrets; print(secrets.token_urlsafe(48))"
AURORA_SECRET_KEY=changeme-generate-a-real-secret
# Comma-separated API keys allowed to call /api/v1/admin/* endpoints.
AURORA_ADMIN_API_KEYS=changeme-admin-key
# --- CORS ---
CORS_ORIGINS=http://localhost:3000,http://localhost:5173
# --- Providers ---
# https://www.themoviedb.org/settings/api
TMDB_API_KEY=
# --- Workers ---
WORKER_CONCURRENCY=4
# --- Caching ---
CACHE_DEFAULT_TTL=300
# --- Rate limiting ---
RATE_LIMIT_ENABLED=true
RATE_LIMIT_PER_MINUTE=120
# --- Artwork storage ---
# Local disk, shared between the api and worker containers via a volume
# (see docker-compose.yml) -- the worker downloads here, the api serves it.
MEDIA_ROOT=./media
MEDIA_URL_PREFIX=/media
ARTWORK_DOWNLOAD_MAX_BYTES=15728640
# --- Production only (docker-compose.prod.yml) ---
# Not used by docker-compose.yml (local dev) or the app itself directly --
# only interpolated into the postgres/pgbouncer service definitions.
# Generate POSTGRES_PASSWORD with a URL-safe generator, not `openssl rand
# -base64`: base64 output can contain `/+=`, which breaks pgbouncer's (and
# any DATABASE_URL parser's) naive URL parsing.
POSTGRES_USER=aurora
# python3 -c "import secrets; print(secrets.token_urlsafe(32))"
POSTGRES_PASSWORD=changeme-generate-a-real-password
POSTGRES_DB=aurora_core