| name | apex-user-and-permission-checks |
| description | Use when Apex needs to check what the running user is, can see, or can do — via UserInfo, FeatureManagement, FeatureManagement.checkPermission, or FeatureManagement.checkPermissionType. Covers custom permissions, permission sets, user licenses, and profile checks. NOT for FLS/CRUD (use Security.stripInaccessible or `with user_mode`), sharing rules, or external user license logic. |
| category | apex |
| salesforce-version | Spring '25+ |
| well-architected-pillars | ["Security","Reliability"] |
| triggers | ["check if the running user has a specific custom permission","different code path for internal vs community users","is this user a System Administrator — how do I check without hardcoding profile name","FeatureManagement.checkPermission returns false unexpectedly","gate a feature on a permission set rather than a profile"] |
| tags | ["apex-user-and-permission-checks","feature-management","custom-permissions","user-context"] |
| inputs | ["the permission or identity property being checked","the caller's context (trigger, LWC imperative, Queueable)","whether the check is for gating UI or enforcing server-side authorization"] |
| outputs | ["correct use of `FeatureManagement.checkPermission('API_Name')` for custom permissions","guidance on Profile-name checks vs Permission Set checks","patterns for internal vs community user branching"] |
| dependencies | [] |
| version | 1.0.0 |
| author | Pranav Nagrecha |
| updated | 2026-04-23T00:00:00.000Z |
Apex User And Permission Checks
Activates when Apex needs to branch on who the running user is or what they are allowed to do. Produces correct FeatureManagement.checkPermission usage, safe identity reads, and guidance to use custom permissions over profile-name checks.
Before Starting
- What are you actually gating — UI behavior only, or server-side authorization? Server-side checks must be enforced with
stripInaccessible / user_mode regardless of permission flags.
- Does a Custom Permission exist for this concept? If not, create one — it's the supported extensibility point.
- Is the check supposed to ignore admins (e.g., "even admins can't do this") or honor them (most permissions do)? Custom Permissions respect "Modify All Data."
- Does this run in a Queueable, Batch, or
@future? The running user is the async context user, not the originating user.
Core Concepts
Prefer Custom Permissions Over Profile / Permission-Set Name Checks
The supported way to gate a feature in Apex is a Custom Permission. In Setup create Perform_Bulk_Refund, assign it to permission sets or profiles, and check with FeatureManagement.checkPermission('Perform_Bulk_Refund'). This returns true if the user has the permission via any assignment path.
Checking Profile.Name == 'Sales Manager' is brittle: the name can be renamed in production, cloned profiles drift, and this check misses permission-set-based grants.
UserInfo Gives Identity, Not Authorization
UserInfo.getUserId(), .getUserName(), .getProfileId(), and .getSessionId() report identity. Use them for logging and relationship lookups. Don't use UserInfo.getProfileId() to drive authorization — couple the gate to a permission the admin can grant.
Async Context Switches The User
Apex in @future, Queueable, Batch, Scheduled, and platform event triggers runs as the async context user (often the user who fired the async, but for scheduled jobs the scheduler, for platform events the "Automated Process" user). FeatureManagement.checkPermission then checks that user's permissions. If you need the originating user, pass their Id explicitly and look up permissions via a query (see patterns).
Custom Permission Lookup Paths
FeatureManagement.checkPermission('Name') checks if the has the custom permission via Profile or Permission Set assignment. Multi-permission checks need an AND/OR logic built in Apex.