Documentation Index
Fetch the complete documentation index at: https://docs.aspfox.com/llms.txt
Use this file to discover all available pages before exploring further.
Adding a new permission
Step 1: Add the permission constant to Permissions.cs in Domain:
// src/Acme.Domain/Constants/Permissions.cs
public static class Permissions
{
// existing permissions...
public const string TenantProjectsRead = "tenant.projects.read";
public const string TenantProjectsManage = "tenant.projects.manage";
}
Step 2: Add the new permissions to the appropriate built-in roles in GetPermissionsForRole():
// src/Acme.Domain/Services/RolePermissionService.cs
public static IReadOnlyList<string> GetPermissionsForRole(string roleName)
{
return roleName switch
{
RoleNames.Owner => new[]
{
// all existing permissions...
Permissions.TenantProjectsRead,
Permissions.TenantProjectsManage,
},
RoleNames.Admin => new[]
{
// existing admin permissions...
Permissions.TenantProjectsRead,
Permissions.TenantProjectsManage,
},
RoleNames.Member => new[]
{
// existing member permissions...
Permissions.TenantProjectsRead,
// Members cannot manage projects by default
},
_ => Array.Empty<string>()
};
}
Step 3: Apply the [HasPermission] attribute to controller actions that require the new permission:
[HttpPost]
[HasPermission(Permissions.TenantProjectsManage)]
public async Task<IActionResult> CreateProject([FromBody] CreateProjectRequest request)
{
// ...
}
[HttpGet]
[HasPermission(Permissions.TenantProjectsRead)]
public async Task<IActionResult> GetProjects()
{
// ...
}
Step 4: Update the frontend usePermissions() hook usage and command palette to show/hide items based on the new permission:
<PermissionGate permission={Permissions.TenantProjectsManage}>
<CreateProjectButton />
</PermissionGate>
Creating custom roles via the API
Any tenant member with the tenant.roles.manage permission can create custom roles:
POST /api/v1/tenants/current/roles
Authorization: Bearer <token>
{
"name": "Developer",
"permissions": [
"tenant.settings.read",
"tenant.members.read",
"tenant.projects.read",
"tenant.projects.manage"
]
}
Updating a custom role:
PUT /api/v1/tenants/current/roles/{roleId}
Authorization: Bearer <token>
{
"name": "Senior Developer",
"permissions": [
"tenant.settings.read",
"tenant.members.read",
"tenant.members.invite",
"tenant.projects.read",
"tenant.projects.manage"
]
}
Deleting a custom role:
DELETE /api/v1/tenants/current/roles/{roleId}
Authorization: Bearer <token>
Deleting a role that has members assigned to it fails with a CONFLICT error. Reassign all members to a different role before deleting.
Permission change propagation
Permissions are embedded in the JWT access token. If you change a role’s permissions — either by editing GetPermissionsForRole() in code or by updating a custom role via the API — affected users continue using the old permissions until their current access token expires (up to 15 minutes) and they get a new one via refresh.There is no built-in mechanism to immediately revoke access tokens for a specific role change. For permission removals that must take effect immediately, the only option is to force re-authentication for the affected users.
Limitations
- You cannot use built-in role names (
Owner, Admin, Member) for custom roles.
- A role must have at least one permission.
- Permission strings must exactly match constants in
Permissions.cs. Invalid strings are rejected with a validation error.
- The
Owner role cannot be deleted or modified. It always has all permissions.
- Each tenant can have at most one Owner.