SfSkills Domains Docs GitHub

Home / apex / apex-custom-permissions-check

apex-custom-permissions-check

Custom Permissions in Apex: FeatureManagement.checkPermission, $Permission global variable, permission-set gating of feature code, Custom Permission metadata. NOT for creating or assigning the permission in Setup — use admin/custom-permissions. NOT for CRUD/FLS enforcement — use apex/apex-stripinaccessible-and-fls-enforcement.

Open the skill folder on GitHub


Apex Custom Permissions Check

Activate when gating code paths, feature availability, or field-level behavior behind a Custom Permission. Custom Permissions are the platform's feature-flag primitive — declarative on/off tokens assigned via Permission Sets or Profiles that Apex, LWC, formulas, and validation rules can check consistently.

Before Starting

Core Concepts

Custom Permission metadata

<CustomPermission xmlns="http://soap.sforce.com/2006/04/metadata">
    <label>Approve Big Deals</label>
    <isLicensed>false</isLicensed>
</CustomPermission>

API Name is the handle used in Apex / formulas.

Apex check

Boolean canApprove = FeatureManagement.checkPermission('Approve_Big_Deals');
if (!canApprove) throw new AuraHandledException('Not authorized');

Per-user, transaction-cached. Safe to call repeatedly.

Formula / validation rule

$Permission.Approve_Big_Deals returns Boolean for declarative gating.

LWC

import hasApprove from '@salesforce/customPermission/Approve_Big_Deals';

Returns Boolean at module load — evaluate in getters.

Testing

@IsTest
static void canApprove() {
    User u = TestUserFactory.makeUser();
    insert new PermissionSetAssignment(
        AssigneeId = u.Id,
        PermissionSetId = [SELECT Id FROM PermissionSet WHERE Name = 'Big_Deal_Approvers'].Id
    );
    System.runAs(u) { ... }
}

Common Patterns

Pattern: Gate Apex service entry point

public with sharing class ApprovalService {
    public void approve(Id oppId) {
        if (!FeatureManagement.checkPermission('Approve_Big_Deals')) {
            throw new AuraHandledException('Not authorized');
        }
    }
}

Pattern: LWC conditional render

import hasApprove from '@salesforce/customPermission/Approve_Big_Deals';
export default class Approve extends LightningElement {
    get showButton() { return hasApprove; }
}

Pattern: Validation rule gate

AND(ISCHANGED(Status), Status='Approved', NOT($Permission.Approve_Big_Deals))

Decision Guidance

NeedMechanism
Feature flag for code pathCustom Permission
Object CRUDObject permission on Permission Set
Field-level gateFLS on Permission Set
Temporary admin toggleCustom Setting + check
A/B testCustom Permission + assignment script
  1. Define the feature boundary — what code runs for privileged users only.
  2. Create the Custom Permission metadata.
  3. Create a Permission Set granting it; assign to users.
  4. Add FeatureManagement.checkPermission at service entry points.
  5. Mirror the check in LWC and formulas where needed.
  6. Write Apex tests using System.runAs + PermissionSetAssignment.
  7. Document the permission in the feature runbook.

Review Checklist

Salesforce-Specific Gotchas

  1. isLicensed=true requires the user's managed-package license; non-licensed users cannot receive it even if assigned.
  2. Schema.describe for Custom Permissions is deprecated — use FeatureManagement.checkPermission.
  3. Custom Permission grants propagate through Permission Set Groups — audit muting flags on groups.

Output Artifacts

ArtifactDescription
Custom Permission metadataXML file
Permission Set granting the CPMetadata + assignment plan
Apex test classPositive + negative cases with runAs

Package files