feat: password auth + session tokens + user invite#18
Merged
Conversation
…essions table Migrations 010 and 011 — extends workspace_users with bcrypt password columns and creates login_sessions for session-token-based auth.
auth_utils.py wraps bcrypt hash/verify. schemas.py adds LoginResponse, CheckEmailResponse, ChangePasswordRequest, ResetPasswordResponse, and password_temp field to WorkspaceUserRead.
…password, reset-password
- register/login now require password for admin/leader; employees remain email-only
- POST /auth/check-email returns requires_password without leaking user existence
- GET /auth/me validates Bearer token, rolls 30-day session expiry
- DELETE /auth/session revokes server-side session on logout
- POST /auth/change-password; skips old-password check for password_temp accounts
- POST /users/{id}/reset-password generates temp password (admin only)
pytest setup with real PostgreSQL test database. Covers register, login, check-email, /me token validation + rolling expiry, logout, change-password (normal + temp-skip), and reset-password (admin-only).
…ontext - types: add password_temp, LoginResponse, CheckEmailResponse - api/client: inject Authorization header from localStorage session_token - AuthContext: boot via GET /auth/me, store token on login/register, revoke session on logout, expose refreshUser()
…word gate - RegisterScreen: password + confirm fields with min-8 validation - LoginScreen: check-email first, show password field only when required - ForceChangePassword: full-screen blocking modal for password_temp accounts - App.tsx: gate renders ForceChangePassword before main app when password_temp=true
- Reset Password button per row (admin only, non-employee users) - Promotes to ai-leader now intercepts dropdown to generate temp password first - Temp password shown once in modal with copy button
…misc cleanup README redesigned with screenshots and collapsible API sections. admin/reset now deletes workshops/categories/sync_logs in FK order. SECURITY.md contact info updated. TODOS.md added. .gitignore updated.
- POST /users/invite (system-admin only): creates WorkspaceUser with local-{uuid} id,
generates temp password for system-admin/ai-leader roles, returns temp_password in response
- InviteUserRequest / InviteUserResponse schemas
- Frontend: InviteUserModal (email + name + role), "Invite User" button in Users panel header
- useInviteUser React Query mutation + InviteUserResponse type
- Employees get email-only login; privileged roles get a temp password shown once with copy button
…f-strings) - Remove unused ResetPasswordResponse import from auth.py - Remove unused instr_len variable in mock_semantic_enricher.py - Remove f-prefix from two literal strings in pipeline.py - Remove unused pytest imports from conftest.py and test_auth.py Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…imports Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- auth_deps.py was untracked (never committed) — caused backend container crash - add pytest-asyncio to CI install so conftest.py imports succeed Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tests require a real PostgreSQL with pgvector — add service to backend job and wire TEST_DATABASE_URL to localhost. Remove the exit-5 bypass now that the DB is available. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The pgvector/pgvector image has the extension available but it must be explicitly enabled per-database before the vector type can be used. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
login_sessionstable with 30-day rolling expiry; all API requests injectAuthorization: Bearer <token>POST /auth/check-emailreturnsrequires_passwordwithout leaking user existence; login screen adapts accordinglypassword_temp=trueblocks access until user sets a permanent password on first login010_add_password(password_hash + password_temp on workspace_users),011_add_login_sessions(login_sessions table with expiry index)Pre-Landing Review
2 issues (0 critical, 2 informational):
backend/app/routers/users.py(invite endpoint) — read-check-write on email uniqueness without DB unique constraint; two concurrent admin invites for the same email could create duplicates. Low probability (admin-only). Deferred to TODOS.md.backend/tests/test_auth.py— no tests forPOST /users/invite. Deferred to TODOS.md.Eval Results
No prompt-related files changed — evals skipped.
Test plan
🤖 Generated with Claude Code