feat(auth): user management and access control#133
Merged
danielnaab merged 7 commits intomainfrom May 7, 2026
Merged
Conversation
SQLite-backed store managing user_access table with status (approved/pending/revoked) and source tracking (domain/env/admin/request). Supports request, approve, deny, revoke, and auto-approve workflows. Part of #118
requireAdmin gates routes to ADMIN_USERS env var (defaults to danielnaab). requireAuth now optionally accepts an AccessStore and rejects revoked users by clearing their session cookie. Part of #118
OAuth callback now checks: (1) ALLOWED_USERS env var, (2) flexion.us domain bypass (hardcoded), (3) user_access database table. Unknown external users are redirected to request access. Pending and revoked users see appropriate status pages. Part of #118
GET /admin/users shows pending, approved, and revoked users. POST actions for approve, deny, revoke, and add. Protected by requireAdmin middleware (ADMIN_USERS env var). Part of #118
Create access store alongside user store in server.tsx. Mount admin routes at /admin with requireAuth guard. Replace raw HTML in auth and admin pages with design-system JSX components. Part of #118
Thread accessStore through to requireAuth() calls in forms and settings routes, not just /new and /admin. Previously a revoked user with a valid session could still access form and settings routes. Part of #118
Show "Admin" nav item in the header when the logged-in user is in ADMIN_USERS. Derives admin status from user.login + env var in Layout, avoiding changes to 70+ Layout call sites. Also extracts parseAdminUsers helper in middleware to reduce duplication. Part of #118
21217c2 to
4dba0cb
Compare
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
/admin/usersfor managing access (approve/deny/revoke/add users)Story
Closes #118
Acceptance Criteria
notes/story-118-user-management/design.md/admin/usersshows all users by statusTest Plan
bun run checkpasses (1381 tests, lint, typecheck)/admin/usersas admin → see user list with approve/deny/revoke/addReview Notes
Authorization model: Three layers checked in order during OAuth callback:
ALLOWED_USERSenv var (bootstrap/emergency access)flexion.usdomain bypass (hardcoded, not configurable)user_accessSQLite table (request/approval workflow)New env var:
ADMIN_USERS(comma-separated GitHub logins, defaults todanielnaab)Files: 13 files changed, ~1,300 lines added. Core changes in
src/services/auth/access-store.ts(new),src/entrypoints/app/middleware/auth.ts(modified),src/entrypoints/app/routes/auth/index.tsx(rewritten callback),src/entrypoints/app/routes/admin/(new).