Implementing Role-Based Access Control (RBAC)

1. Understanding RBAC Concepts

ElementDefinition
UserIdentity granted access
RoleNamed set of permissions
PermissionAction on resource (e.g., orders:read)
Assignmentuser → role(s); role → permission(s)
SessionSubset of user's roles activated for a session

2. Defining Roles

PracticeDetail
GranularityJob functions, not job titles
NamingVerb-noun: orders.viewer, billing.editor
CountAvoid role explosion (~10-50 well-defined)
ReviewsPeriodic access reviews (SOX, SOC 2)

3. Assigning Permissions to Roles

Example: Schema

CREATE TABLE roles (id SERIAL PRIMARY KEY, name TEXT UNIQUE);
CREATE TABLE permissions (id SERIAL PRIMARY KEY, name TEXT UNIQUE);
CREATE TABLE role_permissions (
  role_id INT REFERENCES roles, permission_id INT REFERENCES permissions,
  PRIMARY KEY (role_id, permission_id)
);
CREATE TABLE user_roles (
  user_id BIGINT, role_id INT, granted_at TIMESTAMPTZ, granted_by BIGINT,
  PRIMARY KEY (user_id, role_id)
);

4. Assigning Roles to Users

MechanismDetail
DirectExplicit assignment
Group-basedUser in group → group has roles
Attribute-drivenJIT from IdP claims (department → role)
Time-boundRole assignment with start/end

5. Implementing Role Hierarchies

admin
  ├── manager
  │     └── employee
  └── auditor (read-only across all)
      
AspectDetail
InheritanceParent role inherits child's permissions
Closure tablePre-compute role ancestors for fast lookup
Cycle preventionDAG enforcement at write time

6. Checking User Permissions

Example: Permission check

@PreAuthorize("hasAuthority('orders:write')")
public Order create(...) { ... }

// Or programmatic
if (!authService.hasPermission(user, "orders", "write", orderId))
  throw new AccessDeniedException();

7. Implementing Role-Based Routing

LayerImplementation
Expressrouter.use("/admin", requireRole("admin"))
Spring@PreAuthorize("hasRole('ADMIN')")
Next.jsmiddleware.ts — redirect if role missing
React RouterGuarded route component

8. Using Role-Based UI Rendering

Example: React permission gate

function Can({ permission, children }) {
  const { permissions } = useAuth();
  return permissions.includes(permission) ? children : null;
}

<Can permission="orders:delete">
  <DeleteButton />
</Can>
Warning: UI-only gating is for UX. ALWAYS enforce permissions server-side.

9. Implementing Dynamic Role Assignment

PatternUse
JIT from IdPProvision on first login from group claim
Self-service requestWorkflow with approvals
Time-bound elevation"Sudo" mode for 30 min
Auto-revokeInactivity-based deprovisioning

10. Managing Role Conflicts

ConflictResolution
SoD (Separation of Duties)Static: cannot hold both; Dynamic: cannot use both in same session
Deny precedenceExplicit deny > allow
UnionMultiple roles → union of permissions
DetectionPeriodic SoD reports

11. Implementing Least Privilege Principle

TacticDetail
Default denyPermission must be explicitly granted
Time-boundTemporary elevation, auto-expire
Scope narrowingPer-resource grants vs blanket
ReviewsQuarterly access certification