---
estimated_steps: 43
estimated_files: 5
skills_used: []
---

# T02: Implement auth API router with registration, login, profile endpoints and integration tests

Create the auth API router with all endpoints (register, login, me, update profile), register it in main.py, seed initial invite codes, and write comprehensive integration tests.

## Steps

1. Create `backend/routers/auth.py` with APIRouter prefix `/api/v1/auth`:
   - `POST /register`: Validate invite code (exists, uses_remaining > 0, not expired), check email uniqueness, hash password, create User, decrement invite code uses_remaining, optionally link creator_id by slug. Return 201 + UserResponse. Errors: 403 invalid/expired code, 409 duplicate email.
   - `POST /login`: Find user by email, verify password, return TokenResponse with JWT. Errors: 401 invalid credentials.
   - `GET /me`: Requires auth (get_current_user dependency). Return UserResponse.
   - `PUT /me`: Requires auth. Accept UpdateProfileRequest — update display_name if provided, verify current_password and set new_password if provided. Return updated UserResponse.
2. In `backend/main.py`, import and include the auth router.
3. Create a seed invite code mechanism: add a function `seed_invite_codes()` in `backend/auth.py` that creates a default invite code if none exist (code='CHRYSOPEDIA-ALPHA-2026', uses_remaining=100). Call it from a startup event or CLI command. For the test suite, create codes in fixtures.
4. Update `backend/tests/conftest.py`: import User, InviteCode, UserRole into the model imports so they're included in `Base.metadata.create_all`. Add an `invite_code` fixture that creates a test invite code. Add a `registered_user` fixture that creates a user via the register endpoint. Add an `auth_headers` fixture that logs in and returns `{"Authorization": "Bearer <token>"}`.
5. Create `backend/tests/test_auth.py` with integration tests:
   - Register with valid invite code → 201 + user created in DB
   - Register with invalid invite code → 403
   - Register with expired invite code → 403
   - Register duplicate email → 409
   - Login with correct credentials → 200 + JWT token
   - Login with wrong password → 401
   - Login with nonexistent email → 401
   - GET /me with valid token → 200 + user profile
   - GET /me with expired/invalid token → 401
   - GET /me without token → 401
   - PUT /me updates display_name → 200 + updated profile
   - PUT /me changes password → 200, can login with new password
   - Existing public endpoints still work without auth (GET /api/v1/techniques, GET /api/v1/creators)

## Must-Haves

- [ ] POST /register with invite code validation, email uniqueness, password hashing
- [ ] POST /login returning JWT
- [ ] GET /me and PUT /me with auth dependency
- [ ] Auth router registered in main.py
- [ ] All 13 integration tests pass
- [ ] Existing public endpoints verified unaffected

## Failure Modes

| Dependency | On error | On timeout | On malformed response |
|------------|----------|-----------|----------------------|
| PostgreSQL (test DB) | Test fails with connection error — check TEST_DATABASE_URL | N/A | N/A |
| bcrypt hashing | Slow on first call (key derivation) — acceptable for test suite | N/A | N/A |

## Negative Tests

- **Malformed inputs**: Register with missing fields → 422, Register with empty password → 422, Login with empty body → 422
- **Error paths**: Invalid invite code → 403, expired invite code → 403, duplicate email → 409, wrong password → 401, invalid JWT → 401, expired JWT → 401
- **Boundary conditions**: Invite code with uses_remaining=1 decrements to 0 and becomes unusable, invite code with uses_remaining=0 rejected

## Verification

- `cd backend && python -m pytest tests/test_auth.py -v` — all tests pass
- `cd backend && python -m pytest tests/test_public_api.py -v` — existing tests still pass (no auth regression)

## Inputs

- `backend/models.py`
- `backend/schemas.py`
- `backend/auth.py`
- `backend/config.py`
- `backend/database.py`
- `backend/main.py`
- `backend/routers/__init__.py`
- `backend/tests/conftest.py`

## Expected Output

- `backend/routers/auth.py`
- `backend/main.py`
- `backend/tests/conftest.py`
- `backend/tests/test_auth.py`

## Verification

cd backend && python -m pytest tests/test_auth.py -v && python -m pytest tests/test_public_api.py -v
