Attribute-Based Access Control (ABAC) system
What is ABAC?
ABAC (Attribute-Based Access Control) is a flexible access control model that makes authorization decisions based on attributes associated with users, resources, actions, and environmental conditions.
ABAC attributes
User attributes: Department, job title, location, ...
Resource attributes: Owner, creation date, file type, sensitivity, ...
Action attributes: Read, write, delete, ...
Environmental attributes: Time of day, location, ...
How were the polilies created?
ABAC uses policies written as rules that combine these attributes. For example, a policy might state: "Allow read access to financial documents if the user is in the Finance department AND it's during business hours AND the request comes from a corporate network."
The advantages
Granular control: Can create particular access rules based on multiple criteria.
Dynamic decisions: Access can change based on real-time conditions like time or location.
Scalability: Doesn't require creating numerous roles for every possible permission combination.
Flexibility: Can easily accommodate new attributes and complex business rules.
Example
Resource
type Todo = {
id: string
title: string
userId: string
completed: boolean
invitedUsers: string[]
}
User
type Role = "admin" | "moderator" | "user"
type User = { blockedBy: string[]; roles: Role[]; id: string; name: string }
Action can performance with the resource
type Permissions = {
todos: {
dataType: Todo
action: "view" | "create" | "update" | "delete"
}
}
Permission checker
type PermissionCheck<Key extends keyof Permissions> =
| boolean
| ((user: User, data: Permissions[Key]["dataType"]) => boolean)
type RolesWithPermissions = {
[R in Role]: Partial<{
[Key in keyof Permissions]: Partial<{
[Action in Permissions[Key]["action"]]: PermissionCheck<Key>
}>
}>
}
// ABAC Permission Rules
const ROLES = {
admin: {
todos: {
view: true,
create: true,
update: true,
delete: true,
},
},
moderator: {
todos: {
view: true,
create: true,
update: true,
delete: (user, todo) => todo.completed,
},
},
user: {
todos: {
view: true,
create: true,
update: (user, todo) =>
todo.userId === user.id || todo.invitedUsers.includes(user.id),
delete: (user, todo) =>
(todo.userId === user.id || todo.invitedUsers.includes(user.id)) &&
todo.completed,
},
},
} as const satisfies RolesWithPermissions
// Permission checker function
function hasPermission<Resource extends keyof Permissions>(
user: User,
resource: Resource,
action: Permissions[Resource]["action"],
data?: Permissions[Resource]["dataType"]
) {
return user.roles.some(role => {
const permission = (ROLES as RolesWithPermissions)[role][resource]?.[action]
if (permission == null) return false
if (typeof permission === "boolean") return permission
return data != null && permission(user, data)
})
}
Action button
const ActionButton = ({ action, resource, data, children, className = "" }) => {
const canPerform = hasPermission(currentUser, resource, action, data);
return (
<button
className={`px-2 py-1 rounded text-sm flex items-center gap-1 ${
canPerform
? `${className} hover:opacity-80`
: 'bg-gray-200 text-gray-400 cursor-not-allowed'
}`}
disabled={!canPerform}
onClick={() => canPerform && alert(`${action} ${resource} - Action would be performed`)}
>
{children}
</button>
);
};
Sample data
const sampleUsers: User[] = [
{ id: "1", name: "John (Admin)", roles: ["admin"] },
{ id: "2", name: "Jane (Moderator)", roles: ["moderator"] },
{ id: "3", name: "Bob (User)", roles: ["user"] },
{ id: "4", name: "Alice (User)", roles: ["user"] }
];
const sampleTodos: Todo[] = [
{ id: "1", title: "Complete project", userId: "1", completed: false },
{ id: "2", title: "Review code", userId: "2", completed: true },
{ id: "3", title: "Team meeting", userId: "3", completed: false },
{ id: "4", title: "Deploy to production", userId: "4", completed: true }
];
Todo Permission Rules
- Admin
- Full access to all todos
- Can view, create, update, and delete
- Moderator
- Can manage all todos
- Can only delete completed todos
- User
- Can view all todos
- Can only edit own todos
- Can edit invited todos
Application demo: https://claude.ai/public/artifacts/9cdc4ba6-d46c-46c0-9829-8b48dd997624
Conclution
ABAC is particularly useful in environments with complex security requirements, such as healthcare systems that need to consider patient relationships, government systems with classification levels, or enterprises with diverse departments and data sensitivity levels. However, it can be more complex to implement and manage than simpler access control models.