Advanced 30 min read

Security.stripInaccessible

By the end of this lesson, you'll be able to:

  • Use Security.stripInaccessible to automatically remove fields a user can't access
  • Explain the problem this method solves compared to manual field checks
  • Apply it before both reading and writing sObject data

Prerequisites: "CRUD and Field-Level Security"

The problem: manual checks don't scale

// Checking every field individually is tedious and easy to forget one
if (Schema.sObjectType.Account.fields.Name.isAccessible()) { /* ... */ }
if (Schema.sObjectType.Account.fields.Industry.isAccessible()) { /* ... */ }
if (Schema.sObjectType.Account.fields.AnnualRevenue.isAccessible()) { /* ... */ }
// ...and so on, for every field a query touches
  1. // Checking every field individually is tedious and easy to forget one — the problem stated up front.
  2. if (Schema.sObjectType.Account.fields.Name.isAccessible()) { /* ... */ } — one check.
  3. if (Schema.sObjectType.Account.fields.Industry.isAccessible()) { /* ... */ } — another check.
  4. if (Schema.sObjectType.Account.fields.AnnualRevenue.isAccessible()) { /* ... */ } — yet another.
  5. // ...and so on, for every field a query touches — for a query selecting 10 fields, this means 10 separate checks — tedious to write, and easy to accidentally miss one when a query changes later.

The one-line fix

List<Account> accounts = [SELECT Id, Name, Industry, AnnualRevenue FROM Account];

SObjectAccessDecision decision = Security.stripInaccessible(AccessType.READABLE, accounts);
List<Account> safeAccounts = decision.getRecords();
  1. List<Account> accounts = [SELECT Id, Name, Industry, AnnualRevenue FROM Account]; — a plain query, no field checks yet.
  2. (blank line)
  3. SObjectAccessDecision decision = Security.stripInaccessible(AccessType.READABLE, accounts); — checks every field on every record against the running user's actual field-level security, in one call.
  4. List<Account> safeAccounts = decision.getRecords(); — returns a cleaned-up version with inaccessible fields automatically removed — no per-field manual checking required.

Using it before a write, too

Account acc = new Account(Name = 'Riverbend Farms', AnnualRevenue = 5000000);

SObjectAccessDecision decision = Security.stripInaccessible(AccessType.CREATABLE, new List<Account>{acc});
List<Account> safeToInsert = decision.getRecords();

insert safeToInsert;
  1. Account acc = new Account(Name = 'Riverbend Farms', AnnualRevenue = 5000000); — a record about to be created.
  2. (blank line)
  3. SObjectAccessDecision decision = Security.stripInaccessible(AccessType.CREATABLE, new List<Account>{acc}); — the same method works before an insert too, with AccessType.CREATABLE.
  4. List<Account> safeToInsert = decision.getRecords(); — stripping out any field the user isn't actually allowed to set.
  5. (blank line)
  6. insert safeToInsert; — before the DML statement runs at all.

Exercise

Given a List<Contact> contacts already queried, use Security.stripInaccessible with AccessType.READABLE and get the cleaned records.

Show hint

Security.stripInaccessible(AccessType.READABLE, contacts).getRecords()

Salesforce: ○ Not connected Connect
APEX

Execution Results

Run your code to see the result.

Security.stripInaccessible Quiz

1. What problem does Security.stripInaccessible solve compared to manual per-field checks?

Log in to submit the quiz and save your score.

My Notes

Log in to keep private notes on this lesson.

Questions about this lesson

No questions yet — be the first to ask.

Log in to ask a question about this lesson.

Summary

Manually checking every single field's accessibility (previous lesson) doesn't scale — Security.stripInaccessible automatically strips out fields the running user can't access from a query result or a record about to be saved.