Permit API Reference
Complete API documentation for @vielzeug/permit.
Core Methods
Permit.register(role, resource, actions)
Registers permissions for a specific role and resource combination.
Parameters:
role: string- The role identifier (e.g., 'admin', 'editor', 'user')resource: string- The resource identifier (e.g., 'posts', 'comments')actions: Partial<Record<PermissionAction, PermissionCheck>>- Permission definitions for each action
Example:
// Static permissions
Permit.register('admin', 'posts', {
view: true,
create: true,
update: true,
delete: true,
});
// Dynamic permissions with functions
Permit.register('author', 'posts', {
update: (user, post) => user.id === post.authorId,
delete: (user, post) => user.id === post.authorId && post.status === 'draft',
});
// Using wildcards
import { WILDCARD } from '@vielzeug/permit';
Permit.register('admin', WILDCARD, {
view: true,
create: true,
update: true,
delete: true,
});Throws:
Error- If role is empty or missingError- If resource is empty or missing
Permit.check(user, resource, action, data?)
Checks if a user has permission to perform a specific action on a resource.
Parameters:
user: T extends BaseUser- User object withidandrolespropertiesresource: string- The resource to check permissions foraction: PermissionAction- The action to check ('view' | 'create' | 'update' | 'delete')data?: D- Optional contextual data for dynamic permission functions
Returns: boolean - true if permission is granted, false otherwise
Example:
const user = { id: '123', roles: ['editor'] };
// Basic check
const canView = Permit.check(user, 'posts', 'view');
// With contextual data for dynamic rules
const post = { id: 'p1', authorId: '123', status: 'draft' };
const canDelete = Permit.check(user, 'posts', 'delete', post);Behavior:
- Checks all user roles (including wildcard role
*) - Returns
trueif ANY role grants permission - Function-based permissions require
dataparameter - Returns
falseif no permissions are found
Permit.clear()
Clears all registered permissions from the registry.
Returns: void
Example:
// Clear all permissions (useful for testing)
Permit.clear();
// Re-register fresh permissions
Permit.register('admin', 'posts', { view: true });Use Cases:
- Resetting permissions between tests
- Re-initializing permission system
- Clearing permissions before loading from database
Permit.roles
Getter that returns a shallow copy of all registered roles and their permissions.
Returns: RolesWithPermissions - Map of roles to their resource permissions
Example:
const allRoles = Permit.roles;
// Inspect registered permissions
for (const [role, resources] of allRoles) {
console.log(`Role: ${role}`);
for (const [resource, actions] of resources) {
console.log(` Resource: ${resource}`, actions);
}
}Note: Returns a shallow copy to prevent direct modification of internal state. Nested Maps are not deep-cloned.
Types
BaseUser
The base user type required for permission checks.
interface BaseUser {
id: string;
roles: string[];
}Properties:
id: string- Unique user identifierroles: string[]- Array of role identifiers
Example:
const user: BaseUser = {
id: 'user-123',
roles: ['editor', 'viewer'],
};PermissionAction
Available permission actions.
type PermissionAction = 'view' | 'create' | 'update' | 'delete';Actions:
'view'- Read/view permission'create'- Create/add permission'update'- Modify/edit permission'delete'- Remove/delete permission
PermissionCheck<T, D>
A permission can be either a static boolean or a dynamic function.
type PermissionCheck<T extends BaseUser, D extends PermissionData> = boolean | ((user: T, data: D) => boolean);Variants:
boolean- Static permission (always true/false)(user, data) => boolean- Dynamic permission based on context
Example:
// Static permission
const staticPermission: PermissionCheck = true;
// Dynamic permission
const dynamicPermission: PermissionCheck = (user, post) => {
return user.id === post.authorId;
};PermissionData
Type alias for contextual data used in permission checks.
type PermissionData = Record<string, any>;This can be any object structure relevant to your permission logic.
Example:
interface Post extends PermissionData {
id: string;
authorId: string;
status: 'draft' | 'published';
}WILDCARD
Exported constant for wildcard matching.
export const WILDCARD = '*';Use this constant to define permissions that apply to all resources or roles.
Example:
import { Permit, WILDCARD } from '@vielzeug/permit';
// Admin has all permissions on all resources
Permit.register('admin', WILDCARD, {
view: true,
create: true,
update: true,
delete: true,
});Advanced Usage
Generic Type Parameters
You can specify custom user and data types for better type safety:
interface CustomUser extends BaseUser {
email: string;
department: string;
}
interface Post {
id: string;
authorId: string;
department: string;
status: string;
}
Permit.register<CustomUser, Post>('manager', 'posts', {
update: (user, post) => {
// Full type inference for user and post
return user.department === post.department;
},
});Combining Multiple Roles
Users can have multiple roles, and permissions are additive:
Permit.register('viewer', 'posts', { view: true });
Permit.register('creator', 'posts', { create: true });
const user = { id: '1', roles: ['viewer', 'creator'] };
Permit.check(user, 'posts', 'view'); // true (from viewer role)
Permit.check(user, 'posts', 'create'); // true (from creator role)
Permit.check(user, 'posts', 'delete'); // false (no role grants this)Wildcard Patterns
Wildcard Resource
// Role has all permissions on ALL resources
Permit.register('admin', WILDCARD, {
view: true,
create: true,
update: true,
delete: true,
});Wildcard Role
// ALL roles have view permission on posts
Permit.register(WILDCARD, 'posts', { view: true });Function-Based Permissions
Function-based permissions receive the user and contextual data:
Permit.register('author', 'posts', {
update: (user, post) => {
// Complex logic
if (post.status === 'published') {
return user.id === post.authorId;
}
return false;
},
});
// Must provide data when checking
const canUpdate = Permit.check(user, 'posts', 'update', post);Important: Function permissions require the data parameter in check(). Without it, the function returns false.
Merging Permissions
Registering permissions for the same role/resource combination merges them:
Permit.register('editor', 'posts', { view: true, create: true });
Permit.register('editor', 'posts', { update: true }); // Merges
// Editor now has: view, create, AND updateInspecting Registered Permissions
// Get all registered permissions
const allPermissions = Permit.roles;
// Check if a specific role exists
const hasRole = allPermissions.has('admin');
// Get permissions for a specific role
const adminPerms = allPermissions.get('admin');
if (adminPerms) {
const postPerms = adminPerms.get('posts');
console.log('Admin post permissions:', postPerms);
}Testing Permissions
import { Permit } from '@vielzeug/permit';
describe('Post Permissions', () => {
beforeEach(() => {
Permit.clear(); // Reset before each test
});
it('allows authors to update their own posts', () => {
Permit.register('author', 'posts', {
update: (user, post) => user.id === post.authorId,
});
const user = { id: '123', roles: ['author'] };
const post = { authorId: '123' };
expect(Permit.check(user, 'posts', 'update', post)).toBe(true);
});
it('denies authors from updating others posts', () => {
Permit.register('author', 'posts', {
update: (user, post) => user.id === post.authorId,
});
const user = { id: '123', roles: ['author'] };
const post = { authorId: '456' };
expect(Permit.check(user, 'posts', 'update', post)).toBe(false);
});
});