Validate CRUD Permission Before SOQL/DML Operation in Salesforce

In Salesforce, while we do development, ensuring data security is important, and we can do that using the CRUD feature. CRUD permissions allow us to define what a user can do with different data types. Validating these permissions before performing SOQL or DML operations helps maintain the security of the org application and protects sensitive data.

In this Salesforce tutorial, I will explain how to validate the CRUD permission before SOQL/DML operations in Salesforce.

CRUD permission validation in Salesforce Apex

Salesforce enforces CRUD and FLS (Field Level Security) at the platform level for declarative tools like standard UI and reports. Not validating the CRUD permissions can lead to unauthorized access to data and create data security issues.

Methods for CRUD Validation in Salesforce Apex

Salesforce provides methods in the Schema.DescribeSObjectResult and Schema.DescribeFieldResult classes to check CRUD and FLS permissions. Below are the methods to validate the CRUD permission in Salesforce.

  • isCreateable(): This method checks permission to create records.
  • isAccessible(): It checks if the user can read records.
  • isUpdateable(): Checks if the user has permission to update records.
  • isDeletable(): Checks if the user has permission to delete records.

Validate Read Permission Before SOQL Query

Validate the user’s read permission before the SOQL query.

Apex Class:

public class getAccounts {
    public void fetchAccounts() {
        if (!Schema.SObjectType.Account.isAccessible()) {
            System.debug('Access to Account records is denied.');
            throw new SecurityException('You do not have permission to access Account records.');
        }

        System.debug('Access to Account records is granted.');
        List<Account> accounts = [SELECT Id, Name FROM Account];
        System.debug('Fetched Accounts: ' + accounts);
    }
}

Calling the class method fetchAccounts to show the output :

getAccounts ga = new getAccounts();
ga.fetchAccounts();

Output:

SOQL query to validate permission in Salesforce

As we can see, the debug statements returned that access is granted, and this way, we can validate the read access for a user in Salesforce SOQL and DML operations using the .isAccessible() method.

Validate Create Permission Before Inserting Records

In this example, we will validate the user’s creation permission before inserting the records through the DML operation. For this, we will use the method .isCreateable() to check the permission to create records.

Apex Class:

public class AccountInsertPermission {
    public void createAccount(Account acc) {
        if (!Schema.SObjectType.Account.isCreateable()) {
            System.debug('Create permission for Account records is denied.');
            throw new SecurityException('You do not have permission to create Account records.');
        }

        System.debug('Create permission for Account records is granted.');
        insert acc;
        System.debug('Inserted Account: ' + acc);
    }
}

Calling the defined validation method createAccount :

Account newAccount = new Account(Name = 'Test Account');
AccountInsertPermission manager = new AccountInsertPermission();
manager.createAccount(newAccount);

Output:

Create permission in Salesforce DML operations

As we can see in the debug, the create permission is validated, and an account is created or inserted. This way, we can validate the create permissions in Salesforce using the .isCreateable() method.

Validate the Update Permissions before updating records.

In this example, I have created a public class, ContactsController, that will retrieve a list of Contact records from the database while ensuring that the fields and objects we’re trying to access can be updated.

In this example, we will check the update records validation for the contact fields Name and Phone, and the method getDecribe will validate that the Contact object itself is updatable.

Apex class code:

public with sharing class ContactsController {

    public static List<Contact> getContacts(Integer queryLimit, Integer queryOffset) {
        List<Contact> contacts = new List<Contact>();
        try {
            if(
                Contact.SObjectType.getDescribe().isUpdateable() &&  
                Schema.SObjectType.Contact.fields.Name.isUpdateable() &&  
                Schema.SObjectType.Contact.fields.Phone.isUpdateable() 
            ) {
              
                System.debug('Query Limit: ' + queryLimit);
                System.debug('Query Offset: ' + queryOffset);

                contacts = [SELECT Id, Name, Phone, Email FROM Contact LIMIT :queryLimit OFFSET :queryOffset];
                
                System.debug('Number of Contacts Retrieved: ' + contacts.size());
            } else {
                System.debug('One or more required fields are not updatable');
            }
        } catch(Exception e) {

            System.debug('Error: ' + e.getMessage());
        }
        return contacts;
    }
}

Calling the validation method:

Integer queryLimit = 5;
Integer queryOffset = 0;

List<Contact> contacts = ContactsController.getContacts(queryLimit, queryOffset);
System.debug('Retrieved Contacts: ' + contacts);

Output:

Validate update permission in Salesforce SOQL

This way, we can validate whether the user can update the specific record or not using the “.isUpdatable()” method.

Validate CRUD permission before SOQL operation using WITH SECURITY_ENFORCED

In Salesforce, the WITH SECURITY_ENFORCED keyword is used to enforce field-level security checks within SOQL queries, which means it only verifies if a user can access specific fields in a SELECT statement.

This clause is only applicable to SELECT queries, not DML operations like INSERT, UPDATE, or DELETE. It verifies if the user can access the fields in the SELECT clause based on their object and field-level permissions.

In this example, we will see the user access to read the contact records using the WITH SECURITY_ENFORCED method.

Apex class code:

public with sharing class ContactsController {

    public static List<Contact> getContacts(Integer queryLimit, Integer queryOffset) {
        List<Contact> contacts;

        try {
            contacts = [
                SELECT Name, Phone
                FROM Contact
                WITH SECURITY_ENFORCED
                LIMIT :queryLimit OFFSET :queryOffset
            ];

            System.debug('Queried Contacts: ' + contacts);

        } catch(System.QueryException qe) {
            System.debug('Query Exception: ' + qe.getMessage());
            contacts = new List<Contact>(); 
        }

        return contacts;
    }
}

Call the validation in the anonymous window.

Integer queryLimit = 10;
Integer queryOffset = 0;

List<Contact> contacts = ContactsController.getContacts(queryLimit, queryOffset);

Output :

Validate CRUD access using with security enforced in Salesforce

In the above apex class, I have applied only the keyword  WITH SECURITY_ENFORCED after Contact in the query to check validation.

This query will return a QueryException if we’re querying a field the current user cannot access. To check that, I called the getContacts method from the anonymous apex window. Then, in the debug window, we got the list of contacts validating the read access of records.

This method of validating record access is useful when validating multiple fields in an object. Then, instead of using the isAccessible() method for all fields, we can use SECURITY_ENFORCED to validate them.

Use the stripInaccessible() method to validate CRUD permission before SOQL

The stripInaccessible() method is used to strip or remove the results of a query that users don’t have access to. The stripInaccessible method is part of the Security class and has two variations, as explained below:

1. stripInaccessible(accessCheckType, sourceRecords, enforceRootObjectCRUD):

  • accessCheckType: This parameter defines the type of access check using the AccessType enum, which includes four possible values: CREATABLE, READABLE, UPDATABLE, and UPSERTABLE.
  • sourceRecords: This is a list of SObjects, where fields that the user cannot access will be removed.
  • enforceRootObjectCRUD: An optional boolean parameter that specifies whether to check for object-level access. By default, this parameter is set to true.

2. stripInaccessible(accessCheckType, sourceRecords):

This version of the method includes only the first two parameters, which work the same as described above. The key difference is that this version does not check for object-level access.

Use the stripInaccessible() method in Apex code:

public with sharing class ContactsController {
    public static List<Contact> getContacts(Integer queryLimit, Integer queryOffset) {
        List<Contact> contacts = [SELECT Name, Phone FROM Contact LIMIT :queryLimit OFFSET :queryOffset];
        System.debug(contacts);
        SObjectAccessDecision decision = Security.stripInaccessible(AccessType.READABLE, contacts, true);
        System.debug(decision.getModifiedIndexes());
        System.debug(decision.getRecords());
        System.debug(decision.getRemovedFields());
        return contacts;
    }
}

Calling the validate method in the apex anonymous window.

Integer queryLimit = 20;
Integer queryOffset = 1;

List<Contact> contacts = ContactsController.getContacts(queryLimit, queryOffset);

Output:

Validate user CRUD permission in Salesforce SOQL query

When attempting to create or update a record, a NoAcessException may occur if you lack access to that record. To handle this situation, you can enclose the operation within a try block and include a catch(NoAccessException e) block to catch and process the exception.

Additionally, the stripInaccessible() method can be utilized with two parameters to filter out inaccessible fields from a list of records. This approach lets you focus your exception handling on the insert, update, or upsert statements within a try-catch block.

This way, by using the above methods for different scenarios, we can validate the user access before retrieving them in the SOQL query or the DML operations.

Conclusion

In this Salesforce tutorial, we learned how to validate the CRUD and Field-Level Security (FLS) permissions in Apex before a SOQL query or DML operation. In the above examples, we have used access validation methods such as .isCreateable(), .isAccessible(), .isUpdateable(), and .isDeletable() to ensure users perform only authorized actions.

The WITH SECURITY_ENFORCED simplifies field-level validation for a user in SOQL. The stripInaccessible() method effectively filters inaccessible fields or records, which is helpful in bulk operations.

You may also like to read:

Agentforce in Salesforce

DOWNLOAD FREE AGENTFORCE EBOOK

Start with AgentForce in Salesforce. Create your first agent and deploy to your Salesforce Org.

Salesforce flows complete guide

FREE SALESFORCE FLOW EBOOK

Learn how to work with flows in Salesforce with 5 different real time examples.