@bernierllc/permission-checker
v0.3.0
Published
Atomic permission checking utilities for role-based access control
Downloads
189
Readme
@bernierllc/permission-checker
A comprehensive role-based access control (RBAC) and policy-based access control (PBAC) system for Node.js applications.
Features
- Role-Based Access Control (RBAC): Define roles with permissions and assign them to users
- Policy-Based Access Control (PBAC): Create complex policies with priority-based evaluation
- Role Inheritance: Roles can inherit permissions from other roles
- Conditional Permissions: Support for time-based, IP-based, and custom conditions
- Caching: Built-in caching for performance optimization
- Validation: Comprehensive validation for all permission entities
- TypeScript: Full TypeScript support with strict typing
Installation
npm install @bernierllc/permission-checkerQuick Start
import { PermissionChecker, Permission, Role, User } from '@bernierllc/permission-checker';
// Create a permission checker instance
const checker = new PermissionChecker();
// Define permissions
const readPermission: Permission = {
id: 'read-users',
name: 'Read Users',
resource: 'users',
action: 'read'
};
// Define a role
const userRole: Role = {
id: 'user',
name: 'User',
permissions: ['read-users']
};
// Define a user
const user: User = {
id: 'user1',
roles: ['user']
};
// Add everything to the checker
checker.addPermission(readPermission);
checker.addRole(userRole);
checker.addUser(user);
// Check permissions
const result = checker.checkPermission({
user,
resource: 'users',
action: 'read'
});
console.log(result.allowed); // trueCore Concepts
Permissions
Permissions define what actions can be performed on what resources.
interface Permission {
id: string;
name: string;
description?: string;
resource: string;
action: string;
conditions?: PermissionCondition[];
}Roles
Roles group permissions together and can be assigned to users.
interface Role {
id: string;
name: string;
description?: string;
permissions: string[]; // Permission IDs
inherits?: string[]; // Role IDs to inherit from
}Users
Users have roles and can optionally have direct permissions.
interface User {
id: string;
roles: string[]; // Role IDs
permissions?: string[]; // Direct permission IDs (optional)
metadata?: Record<string, any>;
}Policies
Policies provide fine-grained control with priority-based evaluation.
interface Policy {
id: string;
name: string;
description?: string;
rules: PolicyRule[];
priority: number; // Higher numbers = higher priority
enabled: boolean;
}Advanced Usage
Role Inheritance
const readerRole: Role = {
id: 'reader',
name: 'Reader',
permissions: ['read-users']
};
const writerRole: Role = {
id: 'writer',
name: 'Writer',
permissions: ['write-users'],
inherits: ['reader'] // Inherits read permissions
};
const user: User = {
id: 'user1',
roles: ['writer']
};
// User will have both read and write permissions
const permissions = checker.getUserPermissions('user1');Conditional Permissions
const timeRestrictedPermission: Permission = {
id: 'time-limited-read',
name: 'Time Limited Read',
resource: 'data',
action: 'read',
conditions: [{
type: 'time',
operator: 'between',
field: 'timestamp',
value: [startTime, endTime]
}]
};
const result = checker.checkPermission({
user,
resource: 'data',
action: 'read',
context: { timestamp: new Date() }
});Policy-Based Access Control
const denySensitivePolicy: Policy = {
id: 'deny-sensitive',
name: 'Deny Sensitive Data',
priority: 200,
enabled: true,
rules: [{
effect: 'deny',
resources: ['sensitive-data'],
actions: ['*'],
conditions: [{
type: 'ip',
operator: 'not_in',
field: 'ipAddress',
value: ['192.168.1.1', '192.168.1.2']
}]
}]
};
checker.addPolicy(denySensitivePolicy);Caching
The permission checker includes built-in caching for performance:
// Disable caching
const checker = new PermissionChecker({ cacheEnabled: false });
// Set custom cache TTL (in milliseconds)
const checker = new PermissionChecker({ cacheTTL: 60000 }); // 1 minute
// Clear cache
checker.clearCache();
// Invalidate specific cache entries
checker.invalidateCache('user1');API Reference
PermissionChecker
Constructor
new PermissionChecker(options?: {
cacheEnabled?: boolean;
cacheTTL?: number;
})Methods
Permission Management
addPermission(permission: Permission): voidremovePermission(permissionId: string): void
Role Management
addRole(role: Role): voidremoveRole(roleId: string): voidgetRolePermissions(roleId: string): Permission[]
User Management
addUser(user: User): voidremoveUser(userId: string): voidassignRoleToUser(userId: string, roleId: string): voidremoveRoleFromUser(userId: string, roleId: string): voidgetUserPermissions(userId: string): Permission[]
Permission Checking
checkPermission(check: PermissionCheck): PermissionResult
Policy Management
addPolicy(policy: Policy): voidremovePolicy(policyId: string): void
Cache Management
clearCache(): voidinvalidateCache(pattern?: string): void
Validation Utilities
import {
validatePermission,
validateRole,
validateUser,
validatePolicy,
generateId
} from '@bernierllc/permission-checker';
// Validate entities before adding them
const validation = validatePermission(permission);
if (!validation.isValid) {
console.log('Errors:', validation.errors);
console.log('Warnings:', validation.warnings);
}
// Generate unique IDs
const permissionId = generateId('permission');Condition Types
Time Conditions
{
type: 'time',
operator: 'between',
field: 'timestamp',
value: [startTime, endTime]
}IP Conditions
{
type: 'ip',
operator: 'in',
field: 'ipAddress',
value: ['192.168.1.1', '192.168.1.2']
}Resource Conditions
{
type: 'resource',
operator: 'equals',
field: 'owner',
value: 'user123'
}Custom Conditions
{
type: 'custom',
operator: 'in',
field: 'department',
value: ['engineering', 'product']
}Operators
equals: Exact matchnot_equals: Not equalin: Value is in arraynot_in: Value is not in arraygreater_than: Numeric comparisonless_than: Numeric comparisonbetween: Value is between two numbers (inclusive)
Performance Considerations
- Caching: Enable caching for frequently checked permissions
- Role Hierarchy: Keep role inheritance chains short
- Policy Priority: Use higher priorities sparingly
- Condition Evaluation: Complex conditions impact performance
Best Practices
- Use Descriptive IDs: Use kebab-case for IDs (e.g.,
read-users) - Validate Input: Always validate permissions, roles, and users before adding
- Cache Strategically: Enable caching for read-heavy workloads
- Monitor Performance: Watch for slow permission checks in production
- Test Thoroughly: Test complex permission scenarios
Examples
See the examples/ directory for comprehensive usage examples:
- Basic RBAC setup
- Policy-based access control
- Conditional permissions
- Role inheritance
- Caching strategies
License
ISC License - see LICENSE file for details.
Contributing
This package is part of the Bernier LLC tools ecosystem. Please follow the project's contribution guidelines.
