Managing who can see what and do what in an application is a critical, yet often complex, challenge. As applications grow, simple, hardcoded permission checks quickly become a tangled mess, leading to security vulnerabilities and maintenance headaches. Role-Based Access Control (RBAC) offers a scalable and manageable solution, and with the right tools, it can be surprisingly simple to implement.
Enter directories.do. While you might think of it as an API for managing files and folders, its true power lies in its flexibility. By leveraging custom metadata, you can transform a simple directory structure into a powerful, programmable access control system.
This post will guide you through implementing a robust RBAC system using the directories.do API, turning complex permission logic into clean, automated, and code-driven workflows.
Role-Based Access Control (RBAC) is a security paradigm that controls access based on the roles of individual users within an enterprise. Instead of assigning permissions directly to users, you assign permissions to roles (e.g., admin, editor, viewer), and then assign users to those roles.
This approach offers several key advantages:
Traditionally, implementing RBAC involves creating and managing multiple database tables: one for users, one for roles, one for permissions, and a pivot table to link them all together. This works, but it decouples your access logic from your data's structure.
The directories.do API offers a more integrated approach. By attaching flexible JSON metadata to each directory, you can define and store access control rules directly alongside the resources they protect. This turns your API directory into a single source of truth for both structure and security.
Here’s how our building blocks map to RBAC concepts:
Let's build a simple RBAC system for a multi-team project structure. We'll define admin, editor, and viewer roles.
First, we'll use the SDK to create a new project directory. During creation, we'll attach metadata that defines our access control list (ACL). We'll assign specific user IDs and group IDs (e.g., team-eng-leads) to our roles.
import { Directories } from '@do-sdk/core';
// Initialize the Directories agent
const directoryService = new Directories();
console.log('Creating a new project directory with RBAC metadata...');
// Create a directory with an access control policy in its metadata
const newProjectDirectory = await directoryService.create({
path: '/projects/project-phoenix/financials',
metadata: {
ownerId: 'user-id-101', // The user who owns this resource
accessControl: {
// Roles are mapped to an array of user or group IDs
'admin': ['user-id-101', 'group-id-exec'],
'editor': ['group-id-finance'],
'viewer': ['team-phoenix-leads']
}
},
recursive: true
});
console.log(
'Successfully created directory:',
newProjectDirectory.path,
'with metadata:',
newProjectDirectory.metadata
);
In this example, the directory /projects/project-phoenix/financials is now programmatically aware of its own access rules.
The next step is to enforce these rules. Your application's backend can query a directory's metadata before performing an action. This creates an agentic workflow where your code actively checks and enforces permissions based on the directory's state.
Here's a conceptual function showing how you could check if a user has permission to perform an action.
// This is a conceptual helper function for your application logic
async function canPerformAction(userId: string, userGroups: string[], action: string, path: string): Promise<boolean> {
// Define which roles are allowed to perform which actions
const rolePermissions = {
'read': ['admin', 'editor', 'viewer'],
'write': ['admin', 'editor'],
'delete': ['admin']
};
try {
const directory = await directoryService.get({ path });
const acl = directory.metadata?.accessControl;
if (!acl) {
console.warn(`No accessControl metadata found on ${path}. Defaulting to deny.`);
return false; // Principle of least privilege
}
// Find all roles the user belongs to for this specific directory
const userRoles = Object.keys(acl).filter(role => {
const assignedIds = acl[role] as string[];
return assignedIds.includes(userId) || assignedIds.some(id => userGroups.includes(id));
});
// Check if any of the user's roles grant the required permission
for (const role of userRoles) {
if (rolePermissions[action]?.includes(role)) {
return true; // Permission granted!
}
}
return false; // No matching role has the required permission
} catch (error) {
console.error(`Error checking permissions for ${path}:`, error);
return false;
}
}
// --- Example Usage ---
const currentUser = { id: 'user-id-205', groups: ['group-id-finance'] };
const hasWriteAccess = await canPerformAction(
currentUser.id,
currentUser.groups,
'write',
'/projects/project-phoenix/financials'
);
console.log(`User ${currentUser.id} has 'write' access: ${hasWriteAccess}`); // true
const hasDeleteAccess = await canPerformAction(
currentUser.id,
currentUser.groups,
'delete',
'/projects/project-phoenix/financials'
);
console.log(`User ${currentUser.id} has 'delete' access: ${hasDeleteAccess}`); // false
Note: This pattern can be expanded to recursively check parent directories for inherited permissions, making it even more powerful.
Needs change. A user might join a new team or get a promotion. With this model, updating access is a simple metadata update.
Let's grant viewer access to a new team.
// Grant the marketing team 'viewer' access
const path = '/projects/project-phoenix/financials';
// 1. Get the current directory state
const directory = await directoryService.get({ path });
const currentAcl = directory.metadata.accessControl;
// 2. Modify the metadata in your code
const newViewers = [...currentAcl.viewer, 'group-id-marketing'];
const updatedAcl = { ...currentAcl, viewer: newViewers };
// 3. Push the update
const updatedDirectory = await directoryService.update({
path,
metadata: {
...directory.metadata,
accessControl: updatedAcl
}
});
console.log('Updated ACL:', updatedDirectory.metadata.accessControl);
This method of directory management provides a powerful foundation for your application's security model. The hierarchical nature of directories is a perfect match for organizational structures, and the flexible metadata allows you to define rules that are as simple or as complex as you need.
By centralizing access control logic within the directory's metadata, you create a system that is:
Ready to move beyond complex permission tables? Organize, Automate, and Scale your access control with directories.do. Explore our documentation to learn more about metadata, or sign up for an API key and start building today.