In modern SharePoint solutions, especially those built with SPFx, controlling granular permissions is crucial for security and governance.
This article walks you through.
- Creating custom role definitions in SharePoint
- Assigning permissions dynamically at the item level
- Implementing best practices for permission auditing
We’ll use the latest PnPjs (spfi) syntax for optimized, tree-shakable code.
1. Setting up PnPjs in SPFx
Install dependencies
import { spfi } from "@pnp/sp";
import { SPFx } from "@pnp/sp/presets/all";
export const getSP = (context: any) =>
spfi().using(SPFx(context));
Usage in your web part.
const sp = getSP(this.context);
2. Creating a Custom Role Definition
SharePoint supports custom role definitions, which are essentially custom permission levels.
import "@pnp/sp/roles";
const roleName = "Custom Reviewer";
const roleDescription = "Can view and add comments, but not edit core data.";
try {
const newRole = await sp.web.roleDefinitions.add(
roleName,
roleDescription,
1073741825, // Permission mask (Read + Add Items)
0 // RoleTypeKind: 0 = None (custom)
);
console.log("Custom Role Created:", newRole);
} catch (err) {
console.error("Error creating custom role definition", err);
}
Tip: You must know the base permission mask value. You can combine permissions using BasePermissions.
3. Assigning Permissions Dynamically at the Item Level
When assigning permissions per list item, break inheritance first.
import "@pnp/sp/security";
const listTitle = "Projects";
const itemId = 12; // Example item
const groupName = "Custom Contributors";
const roleNameToAssign = "Custom Reviewer";
// Break inheritance
await sp.web.lists.getByTitle(listTitle).items.getById(itemId).breakRoleInheritance(true);
// Get group and role
const group = await sp.web.siteGroups.getByName(groupName)();
const role = await sp.web.roleDefinitions.getByName(roleNameToAssign)();
// Assign role to group
await sp.web.lists.getByTitle(listTitle).items.getById(itemId)
.roleAssignments.add(group.Id, role.Id);
console.log(`Assigned ${roleNameToAssign} to ${groupName} for item ${itemId}`);
4. Auditing Permissions
Permission auditing is essential to ensure compliance and security.
You can retrieve and log all role assignments for a list, library, or item.
const assignments = await sp.web.lists
.getByTitle(listTitle)
.items.getById(itemId)
.roleAssignments
.expand("Member", "RoleDefinitionBindings")();
assignments.forEach(a => {
console.log(`Member: ${a.Member.Title}`);
a.RoleDefinitionBindings.forEach(r => console.log(` - Role: ${r.Name}`));
});
This is helpful for security reviews or diagnosing unexpected access.
Best Practices for Permission Management
- Prefer Group Assignments Over Direct User Assignments: Groups make future maintenance easier.
- Document Custom Roles: Keep a record of permission masks and role purposes.
- Audit Regularly: Use automated scripts to check for over-permissioned accounts.
- Avoid Excessive Item-Level Permissions: Too many unique permissions can hurt performance.
- Reset Inheritance When Appropriate: Clean up permissions when items no longer need custom access.
Conclusion
Using PnPjs v3+, you can create custom role definitions, assign permissions dynamically per item, and audit permissions programmatically giving you fine-grained control over SharePoint security inside your SPFx solutions.
Next in the Series
We’ll explore automating site-wide permission frameworks, including.
- Role mapping templates
- Self-service access requests
- Automated cleanup jobs
Helpful References