Role-Based Access Control (RBAC)
Agentlang provides a declarative, schema-level mechanism for specifying role-based access control (RBAC). This system governs who can perform specific actions (Create, Read, Update, Delete) on entities or records in an Agentlang application.
RBAC rules are expressed using the @rbac annotation on entity definitions or attributes.
3.1 Overview
The @rbac annotation defines one or more permission specifications, each describing:
- roles — which user roles the rule applies to
- allow — what operations are permitted
- where (optional) — an expression constraining when the rule applies
Syntax
@rbac [
(roles: [<role1>, <role2>, ...], allow: [<op1>, <op2>, ...] [, where: <condition>])
...
]Operations
The following operations are supported:
| Operation | Meaning |
|---|---|
create | Permission to create new instances |
read | Permission to read or query instances |
update | Permission to modify instances |
delete | Permission to delete instances |
Example
entity Department {
deptNumber Int @id,
deptName String,
@rbac [(roles: [manager], allow: [create])]
}Meaning:
Only users with the manager role can create instances of Department.
3.2 Ownership Semantics
When a user creates an entity instance:
- That user automatically becomes the owner of the instance.
- The owner has full CRUD permissions on that instance and all child entities in a
containshierarchy. - Users with the
adminrole have full CRUD access to all entities, regardless of RBAC rules.
3.3 Fine-Grained User Permissions
Permissions can also be assigned at the user level using RBAC rules that include a where clause.
Example
entity User {
id UUID @id,
name String,
@rbac [
(roles: [*], allow: [create]),
(allow: [read], where: auth.user = this.id)
]
}Explanation:
- Any user (
*wildcard role) can create newUserentities. - A user can only read their own user record (where
auth.userequalsthis.id).
3.4 The agentlang.auth Module
The built-in agentlang.auth module defines the core schema for managing users, roles, and permissions.
It is automatically available in every Agentlang application.
Module Overview
module agentlang.authCore Entities
User
entity User {
id UUID @id @default(uuid()),
email Email @unique @indexed,
firstName String,
lastName String,
@rbac [(allow: [read, delete, update, create], where: auth.user = this.id)],
@after {delete AfterDeleteUser}
}- Represents an authenticated user.
- Can read, update, or delete its own record.
@after {delete AfterDeleteUser}denotes a post-delete hook.
Role
entity Role {
name String @id
}Defines a user role (e.g., admin, manager, employee).
Permission
entity Permission {
id String @id,
resourceFqName String @indexed,
c Boolean,
r Boolean,
u Boolean,
d Boolean
}Each Permission corresponds to CRUD access on a specific resource.
Relationships
relationship UserRole between (User, Role)
relationship RolePermission between (Role, Permission)UserRolelinks users to their assigned roles.RolePermissionlinks roles to their permissions.
3.5 RBAC Workflows
The agentlang.auth module includes several public workflows for managing users, roles, and permissions.
Assign a User to a Role
@public workflow AssignUserToRole {
{User {id? AssignUserToRole.userId}} @as [user];
{Role {name? AssignUserToRole.roleName}} @as [role];
{UserRole {User user, Role role}, @upsert}
}Associates a user (by ID) with a specified role.
@upsert ensures the relationship is created or updated atomically.
Assign a Role by Email
@public workflow AssignUserToRoleByEmail {
{User {email? AssignUserToRoleByEmail.email}} @as [user];
{Role {name? AssignUserToRoleByEmail.roleName}} @as [role];
{UserRole {User user, Role role}, @upsert}
}Convenience variant that assigns roles based on a user’s email.
Create a Permission
@public workflow CreatePermission {
{Permission {
id CreatePermission.id,
resourceFqName CreatePermission.resourceFqName,
c CreatePermission.c,
r CreatePermission.r,
u CreatePermission.u,
d CreatePermission.d
},
RolePermission {Role {name? CreatePermission.roleName}},
@upsert}
}Creates a new permission and associates it with a role.
Add an Existing Permission to a Role
@public workflow AddPermissionToRole {
{Role {name? AddPermissionToRole.roleName}} @as [role];
{Permission {id? AddPermissionToRole.permissionId}} @as [perm];
{RolePermission {Role role, Permission perm}, @upsert}
}Adds a pre-existing Permission entity to a Role.
3.6 Authentication Provider
By default, Agentlang uses AWS Cognito as its authentication and identity provider.
To enable Cognito-based authentication, configure the following environment variables:
export COGNITO_USER_POOL_ID=<cognito-pool-id>
export COGNITO_CLIENT_ID=<cognito-client-id>
export AWS_ACCESS_KEY_ID=<aws-access-key>
export AWS_SECRET_ACCESS_KEY=<secret-key>
export AWS_REGION=<aws-region>Login API
Users can authenticate via an HTTP POST request:
POST agentlang.auth/login
Content-Type: application/json
{"email": "<cognito-user-id>", "password": "<cognito-password>"}Response:
{
"id-token": "<jwt-token>"
}The token must be included in subsequent requests as:
Authorization: Bearer <id-token>Automatic Role Synchronization
- On first login, a local
Userentity is created automatically. - Cognito groups are mapped to roles in Agentlang.
- Thus, role memberships in Cognito are reflected in application-level RBAC.
3.7 Runtime Behavior Summary
| Concept | Description |
|---|---|
| @rbac | Declaratively specifies who can perform which actions |
| roles | Logical groups of users (from Cognito or app-defined) |
| allow | Allowed operations: [create, read, update, delete] |
| where | Conditional expression limiting applicability |
| owner | Creator of an instance with full CRUD on it and children |
| admin | Global role with unrestricted access |
| agentlang.auth module | Provides built-in user, role, and permission schema |
| @upsert | Ensures idempotent relationship updates |
| auth.user | Current authenticated user identifier |
| AWS Cognito integration | Provides user identity and role mapping |
Complete Example
module acme.hr
entity Department {
deptNumber Int @id,
deptName String,
@rbac [(roles: [manager], allow: [create])]
}
entity Employee {
id Int @id,
name String,
department Path,
@rbac [
(roles: [manager], allow: [read, update]),
(allow: [read], where: auth.user = this.owner)
]
}- Only managers can create departments.
- Managers can read or update employees.
- An employee can read their own record.