Skip to main content

Salesforce Basics: Object-Level & Field-Level Security (CRUD/FLS)

๐Ÿ’ฌ In plain words: Two locks on data: object-level (can you touch Accounts at all — Create/Read/Update/Delete) and field-level (okay, but can you see the Salary field?). Sharing decides WHICH records; CRUD/FLS decides WHAT you can do with the object and its fields.
๐Ÿ“Œ Example: Asha can see the Candidate object (object-level ✓) but the Salary field is hidden from her profile (field-level ✗). She opens the record fine — the Salary column is simply not there, even in reports and the API.

Concept

CRUD (object permissions) and FLS (field permissions) are granted via profiles and permission sets. They are enforced automatically in the standard UI, standard controllers, and Lightning Data Service — but NOT automatically in Apex, which runs in system mode by default on legacy API versions.

  • Apex Enforcement: In Apex code, security must be explicitly opted into: SOQL queries with WITH USER_MODE, DML with as user, or Security.stripInaccessible() to sanitize records.
  • Distinction: CRUD/FLS answers "which objects and fields", while record-level sharing answers "which rows".
  • Client-Side: Lightning Data Service (LDS) enforces CRUD and FLS automatically for LWC components without requiring manual server checks.
๐Ÿง  CRUD/FLS vs Sharing: CRUD/FLS = WHICH objects & fields. Sharing = WHICH rows. Apex runs in SYSTEM mode → you must opt in (USER_MODE / stripInaccessible).

Core Q&A

Q: How do you enforce CRUD/FLS in Apex, and which mechanism do you choose when?
๐ŸŽฏ Say this first: Use WITH USER_MODE in SOQL/DML as the default; Security.stripInaccessible for cleaning data; manual describe checks only for special cases.

A: Prefer user-mode database operations: SELECT ... WITH USER_MODE and insert as user records — they enforce CRUD, FLS, and sharing together while reporting all violations.

  • WITH SECURITY_ENFORCED is the older query-only clause that throws on the first violation, ignores polymorphic fields, and does nothing for DML.
  • Security.stripInaccessible(AccessType.READABLE/CREATABLE, records) provides graceful degradation — instead of throwing an exception, it strips fields the user cannot access. This is ideal for integration-facing or bulk execution paths where partial success is acceptable.
  • Rule of Thumb: User mode as the default in new code, stripInaccessible when you must not throw exceptions, and manual Describe checks only for custom UI field-building logic.
// Modern default List<Case> cases = [SELECT Id, Subject FROM Case WHERE Status = 'Open' WITH USER_MODE]; // Graceful degradation SObjectAccessDecision d = Security.stripInaccessible( AccessType.READABLE, cases); return d.getRecords();

Follow-ups (Scenario-Based)

Q1: The standard UI hides a field from a user, but your LWC calling an Apex @AuraEnabled method still shows it. Why, and what are the two distinct fixes?

A1: Because the Apex method runs in system mode: FLS was checked by the standard page layout, not by your custom SOQL query.

  • Fix 1 (Apex): Enforce security in Apex using WITH USER_MODE or Security.stripInaccessible() before returning data to the LWC.
  • Fix 2 (LWC): Eliminate custom Apex reads entirely and use Lightning Data Service (LDS) or the getRecord wire adapter, which automatically enforces CRUD/FLS out of the box with client-side caching.
  • Architect Note: Option 2 is preferred whenever complex server-side data processing is not required.
Q2: A configurable approval engine lets business users change rules without engineering. How do you stop that from becoming a privilege-escalation path?

A2: Implement a strict two-layer security model:

  • Layer 1 (Configuration Access): Configuration objects carry their own strict CRUD/FLS, so only the "Approval Config Author" permission set can create or edit rules.
  • Layer 2 (Execution Context): The engine's evaluation code reads rule configurations without sharing (since system rules evaluate globally), but every action or update on target records executes in USER_MODE.
  • An approver can never view or modify fields forbidden by their own FLS — the engine amplifies process authority, never data authority.

Recommended Reading: Reports, Dashboards & Analytics Architecture