@bemedev/permissions
v0.1.2
Published
A library for managing permissions
Maintainers
Readme
@bemedev/permissions
A modern TypeScript library for permissions management based on the ABAC (Attribute-Based Access Control) model.
🚀 Installation
npm install @bemedev/permissions
# or
pnpm add @bemedev/permissions
# or
yarn add @bemedev/permissions📋 Peer Dependencies
This library requires the following dependencies:
npm install @bemedev/decompose @bemedev/types🎯 Features
- ✨ Permissions machine with complete ABAC system
- 🔧 Flexible strategies:
bypass,and,or - 📝 Complete TypeScript types for type safety
- 🎯 Factory pattern to create instances easily
- 🔒 Role system with priorities
- 📊 Resource management with actions and data types
- 🛡️ Validation of user and data permissions
🏁 Quick Start
Basic Configuration
import { createMachine, typings } from '@bemedev/permissions';
// Define the configuration
const config = typings({
ressources: {
image: {
actions: ['view', 'edit', 'delete'],
dataType: { id: 'string', url: 'string' },
__strategy: 'bypass',
},
document: {
actions: ['read', 'write', 'delete'],
dataType: { id: 'string', content: 'string' },
__strategy: 'and',
},
},
user: { name: 'string', department: 'string' },
roles: { admin: 10, editor: 5, viewer: 1 },
});
// Define permission implementations
const implementation = {
'admin:image:view': true,
'admin:image:edit': true,
'admin:image:delete': true,
'admin:document:read': true,
'admin:document:write': true,
'admin:document:delete': true,
'editor:image:view': true,
'editor:image:edit': true,
'editor:document:read': true,
'editor:document:write': ({ performer, owner }) =>
performer.__id === owner.__id,
'viewer:image:view': true,
'viewer:document:read': true,
};
// Create the permissions machine
const machine = createMachine(config, implementation);Permission Checking
// Define users
const admin = {
__id: 'admin1',
name: 'Alice Admin',
department: 'IT',
roles: ['admin'],
};
const editor = {
__id: 'editor1',
name: 'Bob Editor',
department: 'Marketing',
roles: ['editor'],
};
// Check permissions
const canAdminViewImage = machine.hasPermisions({
performer: admin,
owner: editor,
ressource: 'image',
action: 'view',
data: { id: 'img123', url: 'https://example.com/image.jpg' },
});
console.log(canAdminViewImage); // true
const canEditorDeleteDocument = machine.hasPermisions({
performer: editor,
owner: admin,
ressource: 'document',
action: 'delete',
data: { id: 'doc123', content: 'Document content' },
});
console.log(canEditorDeleteDocument); // false📚 Key Concepts
Strategies
The library supports three validation strategies:
bypass
Ignores data permissions and relies only on user permissions.
{
resource: {
__strategy: 'bypass',
// ...
}
}and
Combines user permissions AND data permissions.
{
resource: {
__strategy: 'and',
// ...
}
}or
Accepts if EITHER user permissions OR data permissions are validated.
{
resource: {
__strategy: 'or',
// ...
}
}Roles and Priorities
Roles have numeric priorities. The higher the number, the higher the priority:
const roles = {
admin: 10, // Maximum priority
editor: 5, // Medium priority
viewer: 1, // Minimum priority
};Dynamic Permissions
Permissions can be static values or dynamic functions:
const implementation = {
// Static permission
'admin:document:view': true,
// Dynamic permission
'editor:document:edit': ({ performer, owner, data }) => {
// Editor can only modify their own documents
return performer.__id === owner.__id;
},
// Permission with field validation
'editor:document:partial': ({ data }) => {
// Returns allowed fields
return ['title', 'content'];
},
};🔧 API Reference
createMachine(config, implementation)
Creates a new permissions machine instance.
Parameters:
config: Typed configuration with resources, user and rolesimplementation: Object containing permission implementations
Returns: Machine instance
machine.hasPermisions(args)
Checks if a permission is granted.
Parameters:
performer: User performing the actionowner: Resource ownerressource: Resource nameaction: Action to performdata: Resource data (optional)
Returns: boolean or string[] (list of allowed fields)
machine.sortRoles(order, ...roles)
Sorts roles by priority.
Parameters:
order:'asc'or'desc'roles: List of roles to sort
Returns: string[]
machine.getPriority(role)
Gets the priority of a role.
Parameters:
role: Role name
Returns: number
📖 Advanced Examples
Permissions with Extra Data
const result = machine.hasPermisions({
performer: user,
owner: owner,
ressource: 'document',
action: 'edit',
data: {
id: 'doc123',
content: 'Document content',
__extraPermissions: {
edit: {
allow: {
id: ['user:editor1'],
content: ['role:editor'],
},
},
},
},
});Managing Users with Multiple Roles
const superUser = {
__id: 'super1',
name: 'Super User',
roles: ['viewer', 'editor', 'admin'], // Multiple roles
};
// The machine will automatically use the role with the highest priorityTesting with vitest-extended
import { createTests } from '@bemedev/vitest-extended';
const { success } = createTests(machine.hasPermisions);
describe(
'Permission Tests',
success({
invite: 'Admin can view images',
parameters: {
performer: admin,
owner: user,
ressource: 'image',
action: 'view',
data: { id: 'img123' },
},
expected: true,
}),
);🤝 Contributing
Contributions are welcome! Please see the contribution guide for more details.
📄 License
MIT
📞 Support
For any questions or issues, feel free to open an issue on GitHub.
👨💻 Author
chlbri ([email protected])
