Build a secure Account service
Ship it safely · Advanced · 25 min · Runs in your Salesforce Developer org · Apex Path
Scenario. A reusable service must not rely on system-mode defaults when it reads or prepares Account data.
Deploy a with-sharing Account service that blocks users without access and strips fields they cannot create.
What you will learn
Saved Apex runs in system mode and ignores user access unless you check. with sharing applies record sharing. WITH USER_MODE makes a query respect user access.
if (!Account.SObjectType.getDescribe().isAccessible()) {
throw new AccessDeniedException('…');
}
SObjectAccessDecision d = Security.stripInaccessible(
AccessType.CREATABLE, candidates
);
Cast each record in d.getRecords() to Account.
Gotcha. stripInaccessible never removes Id — clear it on copies.
The task
Finish the Account service so reads respect the user's access and create copies lose fields the user can't set.
Examples:
- two Account Ids → their names, sorted:
Secure Alpha,Secure Zeta - a user with no Account access calls
readableNames→AccessDeniedException - a queried Account passed to
sanitizeForCreate→ a copy with no SystemModstamp and a null Id
Requirements:
- Keep
with sharing. Return an empty list for null or empty input, with no query. - Throw
AccessDeniedExceptionwhen Account or its Name field is not readable. Otherwise query the IdsWITH USER_MODE, sorted by Name. - Throw
AccessDeniedExceptionwhen Account is not creatable. - Use
Security.stripInaccessible(AccessType.CREATABLE, ...), clear Id on the returned copies, and leave the caller's records unchanged. - The checks also run your class with
System.runAsas a user who can read but not create Accounts, and as a user with no Account access.
Starter code
public with sharing class AS_AD7A552FF932_SecureAccountService {
public class AccessDeniedException extends Exception {}
public static List<String> readableNames(Set<Id> accountIds) {
return new List<String>();
}
public static List<Account> sanitizeForCreate(List<Account> candidates) {
if (candidates == null) {
return new List<Account>();
}
return candidates;
}
}
When it passes
The saved class uses with sharing, reads in user mode, blocks users without access, strips SystemModstamp and clears Id on copies, and leaves the original records alone.
You write the Apex yourself. ApexSensei runs it and tells you what passed and what did not.