In Salesforce, Apex code runs in system mode by default. That means it can access all data, even if the current user doesn’t have permission. This can lead to security issues if you're not careful.
To fix this, Salesforce introduced User Mode – a cleaner and safer way to run SOQL and DML operations as the user.
What is User Mode?
User Mode lets your code automatically respect:
- Field-level security (FLS)
- Object-level security (CRUD)
This means your queries and operations behave just like the user is running them.
How to Use User Mode
You can use User Mode in these operations:
Database.query(new Query("SELECT Name FROM Account").setUserMode(UserMode.CURRENT));
Database.getQueryLocator(new Query("SELECT Name FROM Account").setUserMode(UserMode.CURRENT));
You can also use it with:
- Database.countQuery()
- Database.insert(), update(), delete() – by setting user mode through Database.DMLOptions
Benefits
- No need to manually check FLS or CRUD
- Prevents accidental access to restricted data
- Works across async processes and batch jobs
- Safer and more user-friendly than WITH SECURITY_ENFORCED
Why It Matters
User Mode is the recommended approach by Salesforce. It makes your Apex code more secure, easier to maintain, and aligned with user permissions—automatically.
Here are real-life examples of using User Mode in Apex code to make sure your logic respects user permissions (FLS & CRUD):
Example 1: Querying Accounts Securely in a Controller
Without User Mode (runs in system mode – not secure):
List<Account> accounts = [SELECT Id, Name, Industry FROM Account];
With User Mode (recommended):
Query query = new Query('SELECT Id, Name, Industry FROM Account')
.setUserMode(UserMode.CURRENT);
List<Account> accounts = Database.query(query);
Now the query will return only fields the current user is allowed to access.
Example 2: Batch Apex – Get Records with Respect to User Access
Batch class using User Mode in start method:
global class AccountBatch implements Database.Batchable<SObject> {
global Database.QueryLocator start(Database.BatchableContext BC) {
Query query = new Query('SELECT Id, Name FROM Account')
.setUserMode(UserMode.CURRENT);
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext BC, List<SObject> scope) {
// Process records here
}
global void finish(Database.BatchableContext BC) {}
}
Example 3: Secure DML Operation (Insert)
Without User Mode (may insert data user isn't allowed to):
insert new Account(Name='Test');
With User Mode:
Account acct = new Account(Name='Test');
Database.DMLOptions dmlOpts = new Database.DMLOptions();
dmlOpts.setUserMode(UserMode.CURRENT);
Database.insert(acct, dmlOpts);
If the user doesn’t have create access to the Account object, this insert will fail safely.
Example 4: Reporting Component – Avoid Showing Restricted Fields
Say you’re building a custom report viewer in LWC or Aura and calling Apex:
Query query = new Query('SELECT Name, AnnualRevenue, Industry FROM Account')
.setUserMode(UserMode.CURRENT);
List<Account> result = Database.query(query);
If the user can't see AnnualRevenue, it will automatically be excluded from results — no error, no extra code!
No comments:
Post a Comment