Multi-Role Scenario
In a Multi-Role Scenario, each user in your application can have multiple roles, and permissions are granted based on the combination of all the roles assigned to the user. This scenario is more flexible than the single-role one, as it allows a user to have permissions from multiple roles simultaneously.
Example Setup
Let's imagine you have a file where the authentication user roles for your application are defined. Here's how that could look::
export enum UserRoles {
Admin = "admin",
User = "user",
Moderator = "moderator",
BetaTester = "betaTester",
}
export interface AuthUser {
userId: string;
roles: UserRoles[]; // User can have multiple roles
// other user properties
}
In this example, AuthUser
includes an array of roles, which allows a user to have multiple roles assigned.
Next, let's define a resource model, say ToDoModel
:
export type ToDoModel = {
authorId: string;
title: string;
description: string;
};
Now, let’s consider how we structure the permissions for this model. Here’s how you would organize the access control:
access-control
├── permissions.config.ts
└── index.ts
In permissions.config.ts
, you'll define the structure of your permissions for different resources. For instance:
// access-control/permissions.config.ts
import { ResourceConfig } from "rolebaker";
export interface MyResourceConfig extends ResourceConfig {
resources: {
todos: {
dataType: ToDoModel;
action: "read" | "write" | "delete";
};
betaResource: {
dataType: string;
action: "view";
};
};
}
Here, MyResourceConfig
extends ResourceConfig
and defines two resources: todos
(representing a to-do list) and betaResource
(a special resource only for betaTester
roles). Each resource is associated with actions (like read
, write
, delete
for todos
or view
for betaResource
).
Assigning Permissions
Now, in index.ts
, you’ll specify which users can perform which actions on these resources. Here’s how you can configure it:
// access-control/index.config.ts
import { MyResourceConfig } from "./permissions.config.ts";
import { bakeAuthorization } from "rolebaker";
import { UserRoles, AuthUser } from "your-auth-file";
export const { hasPermission } = bakeAuthorization<
UserRoles,
AuthUser,
MyResourceConfig
>({
userRoleMode: "multiRole", // This defines that users can have multiple roles
permissionsConfig: {
admin: {
todos: { read: true, write: true, delete: true },
},
moderator: {
todos: { read: true, write: false, delete: false },
},
user: {
todos: {
read: true,
write: false,
delete: {
checkFunction: (authUser, todo) => todo?.authorId === authUser.userId, // Allows a user to delete only their own todo
},
},
},
betaTester: {
betaResource: { view: true }, // Only beta testers can view this resource
},
},
});
Permissions Configuration
Here’s what’s happening:
- Admin can read, write, and delete todos.
- Moderator can only read todos and cannot write or delete.
- User can only read todos and has restricted delete permissions (they can only delete their own todos).
- BetaTester can view the special
betaResource
but has no access to todos.
Has Permission?
In this scenario, the hasPermission
function will check if any of the user’s roles allows the action. If any role grants the permission, `the action will be allowed.
// Example
const authorUser: AuthUser = { roles: [UserRoles.User], userId: "user1" };
const resourceData: ToDoModel = {
authorId: "user1",
title: "title",
description: "description",
};
const isAllowed = hasPermission(authorUser, "todos", "delete", resourceData); // true
hasPermission
will return true if any of the user’s roles has permission for the action, and false if none of the roles have permission.