Skip to content

refactor(auth): unify pbac logic and remove hasAdminAccess - #33

Merged
pramodnarayana merged 6 commits into
developmentfrom
feat/granular-permissions-web
Jan 27, 2026
Merged

pramodnarayana merged 6 commits into
developmentfrom
feat/granular-permissions-web

Conversation

@pramodnarayana

@pramodnarayana pramodnarayana commented Jan 27, 2026 •

Copy link
Copy Markdown
Owner
  • Implement granular utility with wildcard support
  • Update to delegates to
  • Add permission to
  • Replace with check in Login/Signup
  • Remove legacy function

Summary by CodeRabbit

  • Refactor
    • Replaced admin-only checks with a generic resource/action permission model and standardized wildcard matching; login and signup routing now rely on the unified permission evaluation.
    • Normalized resource and action names for consistent access decisions across the app.
  • Chores
    • Seeded roles with finer-grained CRUD plus dashboard and settings permissions for more precise RBAC.

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

- Implement granular  utility with wildcard support
- Update  to delegates to
- Add  permission to
- Replace  with  check in Login/Signup
- Remove legacy  function
@coderabbitai

coderabbitai Bot commented Jan 27, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@pramodnarayana has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 13 minutes and 24 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.

📝 Walkthrough

Walkthrough

Replaces a hard-coded admin check with a generic hasPermission(permissions, resource, action) evaluator; updates call sites (login/signup), normalizes frontend resource/action mapping in AccessControlProvider, and expands RBAC seeds to finer-grained resource:action permissions.

Changes

Cohort / File(s) Summary
Auth utility
apps/web/src/lib/auth/utils.ts
Replaced hasAdminAccess(permissions?) with hasPermission(permissions, resource, action) implementing four-match patterns: exact (resource:action), resource:*, *:action, and *. Removed namespace/system-specific special cases.
Auth pages
apps/web/src/pages/auth/LoginPage.tsx, apps/web/src/pages/auth/SignupPage.tsx
Swapped imports/usages of hasAdminAccess for hasPermission(user.permissions, 'dashboard', 'view'); navigation target logic unchanged but permission evaluated via new signature.
Access control provider
apps/web/src/providers/access-control-provider.ts
Introduced RESOURCE_MAP and ACTION_MAP for normalization (strip admin/ prefixes, map frontend actions to backend verbs); delegates checks to hasPermission and updates denial messages to Missing permission: <resource>:<action>.
Identity adapter & seeds
packages/identity/src/adapters/drizzle-permission.adapter.ts, packages/identity/src/scripts/seed-rbac.ts
Adapter: added clarifying comments around permission aggregation (no functional change). Seeds: replaced coarse perms with granular CRUD permissions (users, tenants, dashboard, settings) and updated role→permission mappings accordingly.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Login/Signup Page
  participant Auth as AuthProvider/Session
  participant ACP as AccessControlProvider
  participant PermUtil as hasPermission
  participant Identity as Identity Adapter/DB

  Client->>Auth: request current user + permissions[]
  Auth-->>Client: returns user + permissions[]
  Client->>ACP: ask for route decision (resource, action)
  ACP->>Auth: ensure permissions available (if needed)
  ACP-->>ACP: normalize resource & map action
  ACP->>PermUtil: hasPermission(permissions, resource, action)
  PermUtil->>PermUtil: evaluate patterns (resource:action, resource:*, *:action, *)
  PermUtil-->>ACP: boolean allowed/denied
  ACP-->>Client: return decision (navigate /admin or /dashboard)
  Note over Identity,Auth: Identity seeds provide granular permissions read by Auth/Adapter
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A rabbit hops through lines of code,
Swapping rules for patterns on the road.
resource:action leads the play,
Wildcards twirl and show the way,
Permissions clear — hop, skip, hooray! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes: refactoring auth logic to unify PBAC (permission-based access control) and removing the hasAdminAccess function.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/identity/src/scripts/seed-rbac.ts (1)

59-73: Consider: Redundant permission assignments for owner role.

The owner role is assigned both users:manage and the individual CRUD actions (users:create, users:update, users:delete). The same applies to tenants. If manage is intended to imply full access, the individual CRUD permissions are redundant.

However, if explicit CRUD permissions are needed for granular checks elsewhere, this is acceptable. Please clarify the intent—either:

  1. Remove individual CRUD if manage implies all, or
  2. Document that both are needed for specific check scenarios.
🤖 Fix all issues with AI agents
In `@apps/web/src/providers/access-control-provider.ts`:
- Around line 9-20: The resourceMap mapping for access control (variables:
resource, targetResource, resourceMap) only handles "users" and "tenants" and
will misclassify new frontend resources; update the logic to be defensive by
either expanding resourceMap with expected entries (e.g., "admin/settings" ->
"settings", "admin/dashboard" -> "dashboard") or normalize incoming resource
strings by stripping a leading "admin/" prefix and applying a fallback (e.g.,
use resource.replace(/^admin\//, "") or default to resource) before lookup, and
add a short comment or a console/processLogger warning when an unmapped resource
is encountered so future additions are evident.
- Around line 22-26: The access control check uses targetAction and calls
hasPermission(permissions, targetResource, targetAction) but doesn't normalize
frontend actions like "edit" to the backend's "update", causing useCan({ action:
"edit" }) to fail; update the logic that sets targetAction (the variable
computed from action || "manage") to map "edit" => "update" (and preserve other
actions), then pass the normalized action into hasPermission so checks match the
seeded permissions; reference targetAction and hasPermission in your change and
adjust any callers relying on the previous value (e.g., useCan/TenantList
usage).

In `@packages/identity/src/scripts/seed-rbac.ts`:
- Around line 25-26: The seeded permission with id "dashboard:view" is not
assigned to any role, so update the roleMap in seed-rbac.ts to include
"dashboard:view" for the owner and admin roles (add the permission id to the
arrays for the "owner" and "admin" entries in the roleMap). Ensure the roleMap
keys "owner" and "admin" reference the exact permission string "dashboard:view"
so hasPermission(user.permissions, 'dashboard', 'view') returns true for those
roles.

Comment thread apps/web/src/providers/access-control-provider.ts
Comment thread apps/web/src/providers/access-control-provider.ts Outdated
- access-control-provider: normalize 'admin/' prefix from resources and map frontend actions (edit->update)
- seed-rbac: assign 'dashboard:view' to owner and admin roles
@pramodnarayana
pramodnarayana marked this pull request as draft January 27, 2026 17:58
@pramodnarayana pramodnarayana self-assigned this Jan 27, 2026
@pramodnarayana
pramodnarayana marked this pull request as ready for review January 27, 2026 17:59

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@apps/web/src/providers/access-control-provider.ts`:
- Around line 9-24: The resourceMap entries ("admin/users", "admin/tenants") are
unreachable because targetResource.startsWith("admin/") is handled first; remove
the redundant entries from resourceMap or move the resourceMap lookup before the
startsWith branch if you need non-prefix mappings. Update the normalization
logic in access-control-provider.ts (variables/functions: targetResource,
resourceMap, startsWith, replace) so either (A) delete the admin/* keys from
resourceMap and keep the startsWith replacement, or (B) consult
resourceMap[targetResource] before the startsWith check to allow explicit
mapping, ensuring no dead code remains.

In `@packages/identity/src/scripts/seed-rbac.ts`:
- Around line 59-74: The owner role in roleMap currently lists both broad
permissions like "users:manage" and each CRUD permission; replace the explicit
CRUD entries with resource wildcards (e.g., use "users:*", "tenants:*",
"settings:*" in roleMap under owner) to remove redundancy and rely on
hasPermission wildcard support, and update the seeding logic that creates
permissions (if any) to ensure wildcard permissions ("users:*", "tenants:*",
"settings:*") are created/stored so role assignment remains valid; adjust
references to roleMap and any permission creation functions accordingly.

Comment thread apps/web/src/providers/access-control-provider.ts
Comment on lines 59 to +74
const roleMap: Record<string, string[]> = {
owner: [
"dashboard:view",
"users:manage",
"users:read",
"users:create",
"users:update",
"users:delete",
"tenants:manage",
"tenants:read",
"tenants:create",
"tenants:update",
"tenants:delete",
"settings:manage",
"settings:read",
],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider using resource wildcards to reduce redundancy.

The owner role lists both users:manage and all individual CRUD permissions (users:read, users:create, users:update, users:delete). Since hasPermission supports resource wildcards (users:*), you could simplify this to avoid maintaining duplicate entries.

This is optional since the explicit listing is correct and provides clear audit trails.

♻️ Alternative using wildcards
     owner: [
       "dashboard:view",
-      "users:manage",
-      "users:read",
-      "users:create",
-      "users:update",
-      "users:delete",
-      "tenants:manage",
-      "tenants:read",
-      "tenants:create",
-      "tenants:update",
-      "tenants:delete",
-      "settings:manage",
-      "settings:read",
+      "users:*",
+      "tenants:*",
+      "settings:*",
     ],

Note: This requires seeding users:*, tenants:*, and settings:* as permissions if you want them stored in the database.

🤖 Prompt for AI Agents
In `@packages/identity/src/scripts/seed-rbac.ts` around lines 59 - 74, The owner
role in roleMap currently lists both broad permissions like "users:manage" and
each CRUD permission; replace the explicit CRUD entries with resource wildcards
(e.g., use "users:*", "tenants:*", "settings:*" in roleMap under owner) to
remove redundancy and rely on hasPermission wildcard support, and update the
seeding logic that creates permissions (if any) to ensure wildcard permissions
("users:*", "tenants:*", "settings:*") are created/stored so role assignment
remains valid; adjust references to roleMap and any permission creation
functions accordingly.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@apps/web/src/providers/access-control-provider.ts`:
- Around line 9-24: The resource normalization currently strips the "admin/"
prefix before consulting resourceMap, causing explicit overrides like
"admin/users" in resourceMap to be ignored; change the logic in
access-control-provider so you consult resourceMap first (check
resourceMap[targetResource] and use that mapping if present), and only if there
is no explicit mapping then apply the prefix normalization (use
targetResource.replace(/^admin\//, "")). Also remove redundant entries from
resourceMap or keep them if you want to preserve explicit overrides for specific
keys (refer to variables/function names targetResource and resourceMap in the
diff).

In `@packages/identity/src/scripts/seed-rbac.ts`:
- Around line 25-26: Replace the inconsistent dashboard permission entry { id:
"dashboard:view", action: "view", resource: "dashboard" } with a consistent
read-based permission (e.g., id "dashboard:read" and action "read") so it
matches other resources like "users:read" and "settings:read"; update any
references to "dashboard:view" in permission checks or tests to "dashboard:read"
if present.

Comment thread apps/web/src/providers/access-control-provider.ts
Comment thread packages/identity/src/scripts/seed-rbac.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/identity/src/scripts/seed-rbac.ts (1)

89-100: Consider adding type safety for permission IDs.

The roleMap uses string literals for permission IDs without compile-time validation against standardPerms. A typo in a permission ID would only be caught at runtime when the database insert fails due to foreign key constraints.

♻️ Optional improvement for type safety
+ // Extract permission IDs as a type for compile-time safety
+ const permissionIds = standardPerms.map(p => p.id) as const;
+ type PermissionId = typeof standardPerms[number]['id'];
+ 
- const roleMap: Record<string, string[]> = {
+ const roleMap: Record<string, PermissionId[]> = {
    owner: [
      "dashboard:read",
      // ... rest of permissions
    ],
    // ...
  };

Alternatively, derive the type from standardPerms to ensure permission strings in roleMap are validated at compile time.

🤖 Fix all issues with AI agents
In `@apps/web/src/providers/access-control-provider.ts`:
- Around line 14-35: resourceMap and actionMap are being recreated inside the
can() flow on every call; hoist these static maps to module scope to avoid
per-call allocation and centralize normalization config. Move the const
resourceMap and const actionMap declarations out of the can() function (or
whichever function contains this logic) into top-level module scope in
access-control-provider.ts, keep their keys/values unchanged, and update can()
to reference these top-level variables (ensure no local shadowing of
targetResource or action variables).

Comment thread apps/web/src/providers/access-control-provider.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@apps/web/src/providers/access-control-provider.ts`:
- Around line 13-21: ACTION_MAP contains redundant identity entries ("create":
"create" and "delete": "delete") that are no-ops because the code already falls
back to rawAction; remove those two entries from ACTION_MAP to simplify the map
(or alternatively leave them if you prefer explicit documentation), and ensure
any logic that uses ACTION_MAP (referencing ACTION_MAP and the fallback
rawAction) still works unchanged after removing them.

Comment thread apps/web/src/providers/access-control-provider.ts
@pramodnarayana
pramodnarayana marked this pull request as draft January 27, 2026 19:00
@pramodnarayana
pramodnarayana marked this pull request as ready for review January 27, 2026 19:00
@pramodnarayana
pramodnarayana merged commit 61e50b0 into development Jan 27, 2026
2 checks passed
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.

1 participant