Skip to content

feat(auth): P4-T2 Admin Role Versioning - #236

Merged
2witstudios merged 6 commits into
masterfrom
claude/add-users-schema-admin-routes-4Rako
Jan 24, 2026
Merged

2witstudios merged 6 commits into
masterfrom
claude/add-users-schema-admin-routes-4Rako

Conversation

@2witstudios

@2witstudios 2witstudios commented Jan 24, 2026 •

Copy link
Copy Markdown
Owner

Adds adminRoleVersion field to users schema to detect role changes
and prevent timing attacks during admin role modifications.

Changes:

  • Add adminRoleVersion field to users table (default: 0)
  • Update SessionClaims to include adminRoleVersion
  • Create updateUserRole function that bumps version on role changes
  • Create validateAdminAccess function for DB-level validation
  • Enhance verifyAdminAuth to validate adminRoleVersion at request time
  • Update BaseAuthDetails and VerifiedUser interfaces
  • Add comprehensive integration and unit tests
  • Generate database migration (0044)

Security: This prevents race conditions where a user's admin status
changes between token issuance and request validation.

Addresses vulnerability #12 from security hardening plan.

Summary by CodeRabbit

  • New Features

    • Admin role versioning: user roles now include a version that increments on role changes.
    • Enhanced admin access validation: admin authentication verifies role-version consistency to prevent access after demotion.
  • Data

    • New adminRoleVersion field added to user records and propagated to session/token authentication flows.
  • Tests

    • Comprehensive test suite covering role versioning, session claims, and access-validation scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

Adds adminRoleVersion field to users schema to detect role changes
and prevent timing attacks during admin role modifications.

Changes:
- Add adminRoleVersion field to users table (default: 0)
- Update SessionClaims to include adminRoleVersion
- Create updateUserRole function that bumps version on role changes
- Create validateAdminAccess function for DB-level validation
- Enhance verifyAdminAuth to validate adminRoleVersion at request time
- Update BaseAuthDetails and VerifiedUser interfaces
- Add comprehensive integration and unit tests
- Generate database migration (0044)

Security: This prevents race conditions where a user's admin status
changes between token issuance and request validation.

Addresses vulnerability #12 from security hardening plan.
@coderabbitai

coderabbitai Bot commented Jan 24, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@2witstudios has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 4 minutes and 26 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Adds admin role versioning: a non-null integer adminRoleVersion on users, APIs to update roles and validate admin access by version, propagation of the version through auth/session flows, and tests exercising role updates, demotions, and version-based access control.

Changes

Cohort / File(s) Summary
Database schema & migration
packages/db/drizzle/0044_funny_orphan.sql, packages/db/drizzle/meta/_journal.json, packages/db/src/schema/auth.ts
Add adminRoleVersion integer column (default 0, not null) and migration journal entry.
Auth core: admin role logic
apps/web/src/lib/auth/admin-role.ts
New module exporting updateUserRole(userId, newRole) which updates role and increments adminRoleVersion, and validateAdminAccess(userId, claimedAdminVersion) which checks role and version match.
Auth integration & types
apps/web/src/lib/auth/auth.ts, apps/web/src/lib/auth/index.ts
Add adminRoleVersion: number to VerifiedUser/BaseAuthDetails; populate from session/MCP results; add verifyAdminAuth(request) that validates admin status via validateAdminAccess.
Session layer & claims
packages/lib/src/auth/session-service.ts
Extend SessionClaims and session validation to include adminRoleVersion, and return it in session auth results.
Tests — auth & admin-role
apps/web/src/lib/auth/__tests__/admin-role-version.test.ts, apps/web/src/lib/auth/__tests__/auth.test.ts
Add comprehensive tests for role updates, version increments, demotions, validateAdminAccess behavior, and integrate validateAdminAccess checks into admin auth tests (including failure paths).
Tests — mocks & fixtures
packages/lib/src/permissions/__tests__/enforced-context.test.ts, packages/lib/src/repositories/__tests__/enforced-file-repository.test.ts, apps/processor/src/services/__tests__/user-validator.test.ts
Updated test mocks to include adminRoleVersion: 0 where SessionClaims or user mocks are used.
Desktop minor change
apps/desktop/src/main/index.ts
Rename unused isNewUser param to _isNewUser with a comment; no functional change.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant AuthService as Auth Service\n(verifyAdminAuth)
    participant DB as Database
    participant AdminRole as Admin Role\n(validateAdminAccess)

    Client->>AuthService: Request with token (includes claimed adminRoleVersion)
    AuthService->>DB: verifyAuth / fetch session + user including adminRoleVersion
    DB-->>AuthService: session/user + claimedAdminRoleVersion
    AuthService->>AdminRole: validateAdminAccess(userId, claimedAdminVersion)
    AdminRole->>DB: Query user role & adminRoleVersion
    DB-->>AdminRole: role, adminRoleVersion
    AdminRole->>AdminRole: compare role == 'admin' && versions match
    AdminRole-->>AuthService: true / false

    alt Validation passes
        AuthService-->>Client: VerifiedUser (includes adminRoleVersion)
    else Validation fails
        AuthService-->>Client: null (unauthorized)
    end
Loading
sequenceDiagram
    participant Admin as Admin User
    participant AdminAPI as Admin API\n(updateUserRole)
    participant DB as Database
    participant Validator as validateAdminAccess

    Admin->>AdminAPI: Request role change for user
    AdminAPI->>DB: UPDATE users SET role = newRole, adminRoleVersion = adminRoleVersion + 1 RETURNING ...
    DB-->>AdminAPI: Updated user { id, role, adminRoleVersion }
    AdminAPI-->>Admin: Response with updated user + adminRoleVersion

    Note over Admin,Validator: Subsequent auth with old claimed version
    Admin->>Validator: authenticate with old claimedVersion
    Validator->>DB: SELECT role, adminRoleVersion WHERE id = ...
    DB-->>Validator: role, currentAdminRoleVersion
    Validator->>Validator: detect mismatch -> deny
    Validator-->>Admin: Access denied
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I nudged a field, I bumped a seed,

admin vibes now track each deed.
When roles change paths diverge or blend,
the version tells if trust should end.
Hop on — but only if versions mend. 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(auth): P4-T2 Admin Role Versioning' clearly summarizes the main change—adding admin role versioning to the authentication system with a specific tracking reference.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0dc479602a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +36 to +38
// Validate adminRoleVersion against the database to ensure
// the role hasn't changed since the token was issued
const isValidAdmin = await validateAdminAccess(user.id, user.adminRoleVersion);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Bind adminRoleVersion to token issuance

The new admin-role check doesn’t actually validate a token’s issuance version because verifyAdminAuth passes user.adminRoleVersion that was just read from the database via authenticateSessionRequest/sessionService.validateSession (which returns session.user.adminRoleVersion). That means validateAdminAccess compares the current DB value to itself, so sessions issued before a role change will still be accepted after promotion (or any change) as soon as the DB is updated, which defeats the intended “invalidate old admin tokens” behavior. If you want role changes to invalidate existing sessions, store the adminRoleVersion in the session/token at creation time and compare it to the current DB value (or bump/revoke sessions directly) rather than re-reading it on each request.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified - this is correct. The current implementation fetches adminRoleVersion fresh from the database during session validation (session-service.ts:91,114) and then compares it to the same fresh DB value in validateAdminAccess. This means role changes take effect immediately but don't invalidate existing sessions.

Fix requires adding adminRoleVersion to the sessions table and storing it at session creation time (like tokenVersion). This is a schema migration + code change. Creating a follow-up task.

2witstudios and others added 5 commits January 24, 2026 14:32
- Add adminRoleVersion: 0 to mock user objects in user-validator.test.ts
- Rename isNewUser to _isNewUser in desktop auth exchange (unused param)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Desktop tsconfig has noUnusedLocals: true which doesn't allow
underscore-prefixed unused variables.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The isNewUser param is sent from web OAuth callback to indicate
new signups vs returning users. Pass it through to the dashboard
URL so the web app can show appropriate welcome flow.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add adminRoleVersion: 0 to SessionAuthResult, MCPAuthResult,
SessionClaims, and User mock objects across 60 test files to
match updated schema.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@2witstudios
2witstudios merged commit aeb6616 into master Jan 24, 2026
7 checks passed
@2witstudios
2witstudios deleted the claude/add-users-schema-admin-routes-4Rako branch January 29, 2026 02:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants