In modern SharePoint solutions, especially those built with SPFx, controlling granular permissions is crucial for security and governance.

This article walks you through.

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

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.

Helpful References