Developers / Security

A Guide to Security In Apex: Object, Field, and Record Level

By Jumber Mdivnishvili

Security is probably the most important aspect for any application, and Salesforce projects are not the exception to this. Most people in the Salesforce ecosystem are aware of declarative mechanisms of controlling object, field, and record-level security. However, there is still a misconception about controlling the security in Apex. 

In this article, I will explain how to control object-level, field-level, and record-level security in Apex, as well as system and user modes and how they are different.

Record-Level Security

Sharing Modes

Sharing modes can be defined in the “signature” of the class, which is categorized by the terms “with sharing”, “without sharing”, “inherited sharing”, or omitted. 

Sharing modes control record-level security when querying or doing DML operations – they do not control field level security (FLS) or object level security, nor do they define system or user mode.

With Sharing 

If an Apex class has “with sharing” mode, then queries written in this class will return the records to which a current user has access. DML operations will succeed on records to which the user has access to, so “with sharing” makes an Apex class to respect the record-level security.

Without Sharing

“Without sharing” does not respect record-level security, meaning that the queries written in the class will return all the records that they find. DML operations will then succeed on any record regardless of the access of the current user.

Inherited Sharing

The class with “Inherited sharing” inherits sharing mode from the class which it extends or the class from which its method/variable is called. For example, class A is extending virtual class B, so class C calls a method of A where query/DML is written. 

Then, the sharing mode of C will be inherited by A, and the sharing mode of B will be discarded in this case.

If a class has inherited sharing and is not called by any other class and is not extending any other class, then it will be executed in “with sharing” mode.

No Sharing Mode Specified (Omitted Sharing Mode)

The class with no sharing mode (omitted) inherits sharing mode from the class that it extends or the class from which its method/variable is called. For example, class A is extending virtual class B, so class C calls a method of A where query/DML is written. 

Then, the sharing mode of B will be inherited by A, and the Sharing mode of C will be discarded in this case.

If a class has no sharing mode specified, is not called by any other class, and is not extending any other class, then it will be executed in “without sharing” mode.

Enforcing User Mode for Database Operations

Note: OLS and FLS are discussed separately in the next section of the article, but I have mentioned them here too, since enforcing USER MODE affects not only record-level security but OLS and FLS too.

Apex code, by default, runs in system mode, which means that object level and field level security are not respected, and record level security depends on the sharing keywords of the Apex class (which we discussed above).

However, Salesforce is giving us the option to run Database operations in the running user mode, which means that our queries and DML operations will respect object level, field level, and record level security. When user mode is enforced, the record-level security of the running user is still enforced regardless of the sharing keyword of the Apex class.

Below is an example of how you enforce User mode in queries. So OLS, FLS(discussed in below sections), and record-level security will all be enforced. If a running user does not have access to the Account object or Industry field, a query exception will be thrown.

This is how you enforce user mode in DML operation:

You can also enforce it with the Database class:

Object Level and Field Level Security

Schema Methods

 Before having the possibility to enforce user Mode in Apex, Schema was used to check the necessary access, mimic the user mode, and perform DML operations after validating the user’s required access.

This means object-level access would be checked in this way:

Similarly, field-level access would be checked in this fashion:

Security Class

Security class allows us to check the running user’s field-level permissions. It enables us to strip inaccessible fields from the list of the records and do DML on the records that have populated fields accessible to the current user.

We can check various access types of the user against the sObject fields:

  • CREATABLE: Check the fields of an sObject for create access.
  • READABLE: Check the fields of an sObject for read access.
  • UPDATABLE: Check the fields of an sObject for update access.
  • UPSERTABLE: Check the fields of an sObject for both insert and update access.

If we are checking the running user’s read access for the fields of the list of the records, let’s say each record has ten fields populated and the user has read access to five of them. Then the other five will be just stripped, and the Security.stripInaccessible() method will return the records with only five fields.

For example:

WITH SECURITY_ENFORCED

WITH SECURITY_ENFORCED checks the OLS and FLS of the running user. If the user does not have access to the object specified in the query or to any field specified in the query, an exception will be thrown.

The main limitations of WITH SECURITY_ENFORCED are:

  1. Exceptions are generic – Insufficient permissions: secure query included inaccessible field.
  2. It cannot evaluate polymorphic fields (besides Owner, CreatedBy and LastModifiedBy)
  3. It enforces FLS on the fields written after SELECT and FROM keywords but not on the fields written after WHERE clause or ORDER BY.

User Mode vs. SECURITY_ENFORCED

As you may recall from the previous section of this article, WITH USER_MODE

enforces record-level security. In addition, it enforces OLS and FLS as well.

WITH USER_MODE checks OLS and FLS and gives more specific exception messages than WITH SECURITY_ENFORCED. Also, it considers polymorphic fields and enforces security on all fields – not just on the fields written after SELECT and FROM keywords.

For example:

It also enforces FLS and OLS during DML operations. Let’s consider the example when a user does not have edit access on the Industry field:

Or you can use the Database class:

Final Thoughts

Although Apex code is run in system mode by default, Salesforce still gives us the option to run it in user mode –  or we can enforce only record-level security or only FLS or OLS. 

So Apex is quite flexible in these terms, and we can choose our security level based on the specific scenario. 

Make sure to share your thoughts in the comments below!

The Author

Jumber Mdivnishvili

Jumber is a 7x Certified Salesforce Developer with years of experience of working on Salesforce Sales Cloud, Service Cloud and Experience Cloud.

Leave a Reply