Implementing Role-Based Access Control (RBAC)
1. Understanding RBAC Concepts
| Element | Definition |
|---|---|
| User | Identity granted access |
| Role | Named set of permissions |
| Permission | Action on resource (e.g., orders:read) |
| Assignment | user → role(s); role → permission(s) |
| Session | Subset of user's roles activated for a session |
2. Defining Roles
| Practice | Detail |
|---|---|
| Granularity | Job functions, not job titles |
| Naming | Verb-noun: orders.viewer, billing.editor |
| Count | Avoid role explosion (~10-50 well-defined) |
| Reviews | Periodic 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
| Mechanism | Detail |
|---|---|
| Direct | Explicit assignment |
| Group-based | User in group → group has roles |
| Attribute-driven | JIT from IdP claims (department → role) |
| Time-bound | Role assignment with start/end |
5. Implementing Role Hierarchies
admin
├── manager
│ └── employee
└── auditor (read-only across all)
| Aspect | Detail |
|---|---|
| Inheritance | Parent role inherits child's permissions |
| Closure table | Pre-compute role ancestors for fast lookup |
| Cycle prevention | DAG 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
| Layer | Implementation |
|---|---|
| Express | router.use("/admin", requireRole("admin")) |
| Spring | @PreAuthorize("hasRole('ADMIN')") |
| Next.js | middleware.ts — redirect if role missing |
| React Router | Guarded 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
| Pattern | Use |
|---|---|
| JIT from IdP | Provision on first login from group claim |
| Self-service request | Workflow with approvals |
| Time-bound elevation | "Sudo" mode for 30 min |
| Auto-revoke | Inactivity-based deprovisioning |
10. Managing Role Conflicts
| Conflict | Resolution |
|---|---|
| SoD (Separation of Duties) | Static: cannot hold both; Dynamic: cannot use both in same session |
| Deny precedence | Explicit deny > allow |
| Union | Multiple roles → union of permissions |
| Detection | Periodic SoD reports |
11. Implementing Least Privilege Principle
| Tactic | Detail |
|---|---|
| Default deny | Permission must be explicitly granted |
| Time-bound | Temporary elevation, auto-expire |
| Scope narrowing | Per-resource grants vs blanket |
| Reviews | Quarterly access certification |