Salesforce Apex With, Without, Inherited and Omitted Sharing

In a Salesforce Apex class, we can define the sharing settings to control data access and ensure security within the Salesforce platform. To manage how Apex classes follow record-level access, we use keywords such as with sharing, without sharing, inherited sharing, and omitted sharing in Salesforce Apex.

In this blog, we’ll learn what each of these sharing keywords means, when to use them, and how they affect data visibility in the Apex code.

What is the Use of Sharing Keywords in the Apex Class?

In Salesforce, the sharing model record-level security is managed through Profiles, Sharing settings, Ownership, Role Hierarchy, and Sharing rules. By using the “Sharing keyword“, we can ensure that the apex class we created follows to Salesforce’s record-level sharing rules, which are based on OWD, role hierarchies, and sharing rules.

By default, Apex code runs in system context, which can bypass these rules and expose data that the user should not usually see. To manage this, Apex provides four sharing options: with sharing, without sharing, inherited sharing, and omitting the sharing keyword.

Let’s see the implementation and use case of these four sharing keywords in Salesforce Apex.

Use case scenario:

Let’s consider a scenario where there is a custom object Project_c, and project records are shared by the CEO and the manager. In the Salesforce role hierarchy, the CEO is above the manager, so he will be able to access all project records, but the manager can only share those records owned or shared with him.

To show the output according to sharing rules, I have assigned the CEO role to my profile and the manager role to another user with a Salesforce platform license.

With Sharing Keyword in Salesforce Apex

In a Salesforce Apex class, when we use the ‘With sharing‘ keyword, the code runs in the context of the current user, which means it enforces the sharing rules for the current user. When we use the “With sharing” keyword, then records not shared with the current user are not accessed by the apex code in this context.

According to the above-mentioned scenario, we will run the apec class in the context of a user with a manager role. In this Apex class, we will use the “with sharing” so the code will follow the sharing rules in the context of the current user.

public with sharing class ApexWithSharing {
    public static List<Project__c> getAllProjects() {
        return [
            SELECT Id, Name, Status__c, Owner.Name
            FROM Project__c
            ORDER BY CreatedDate DESC
        ];
    }
}

Now, enter the code below in the anonymous window to execute the apex class method.

List<Project__c> projects = ApexWithSharing.getAllProjects();

for (Project__c project : projects) {
    System.debug('Project Name: ' + project.Name + 
                 ', Status: ' + project.Status__c + 
                 ', Owner Name: ' + project.Owner.Name);
}

In the Execution log window, select the ‘Debug only‘ checkbox, and you will see the records owned by the current user.

Implement with sharing in Salesforce Apex

The current user is getting the records owned by him in the manager role in the role hierarchy. On the other hand, when the CEO can see all the records because he is above in the role hierarchy.

Without Sharing Keyword in Salesforce Apex

In the Salesforce Apex class, the without sharing keyword allows the user to bypass sharing rules and view the details of the records that they do not own.

Now, there are project records, and the user with the manager role wants to know how many active projects there are in the org, so basically, the count of active projects. In this, the user will view the active status of records owned by others.

For this requirement, we create the Apex Class Project Sharing with the code below.

public without sharing class ProjectSharing {
    @AuraEnabled(cacheable=true)
    public static Integer getTotalProjectsCount() {
        return [
            SELECT COUNT()
            FROM Project__c
            WHERE Status__c = 'Working'
        ];
    }
}

To call the apex class method, enter the code below in the anonymous window and execute it.

Integer activeProjectCount = ProjectSharing.getTotalProjectsCount();
System.debug('Total Active Projects: ' + activeProjectCount);

In the Execution log window, select the checkbox, and you will see the record count of the active projects irrespective of whether those records are accessible to the current users or not.

Without Sharing in Salesforce Apex

Inherited Sharing in Salesforce Apex

This Apex sharing feature was introduced in the Winter ’19 release. In the Inherited Sharing feature, we can call the class in both “With Sharing” and “Without Sharing” sharing settings, depending on the context in which the class is called.

This keyword implements the sharing settings as the same as the class in which the current class is called. When we call the inherited sharing class from a with sharing class, it will follow the sharing rules and restrict any data from being accessed.

When the Inherited class is called from the non-sharing class, it will not follow the sharing rules and expose all the data. If we don’t define with or without sharing in the Inherited class, it runs “with sharing” by default.

For example, we have the Inherited Sharing class below, which follows the sharing rules of the class that calls it.

public inherited sharing class ApexInheritedSharing {
    @AuraEnabled(cacheable=true)
    public static List<Project__c> getProjects() {
        return [SELECT Name, Owner.Name FROM Project__c];
    }
}

Calling the Inherited Sharing class from “with sharing class“:

public with sharing class ApexWithSharing {
    @AuraEnabled(cacheable=true)
    public static List<Project__c> getProjectsInherited() {
        return ApexInheritedSharing.getProjects();
    }
}

The above class will return the records owned by the current user because it follows the sharing rules set to “with sharing“.

Anonymous code in the “With Sharing” class to execute it.

List<Project__c> projects = ApexWithSharing.getProjectsInherited();
for (Project__c project : projects) {
    System.debug('Project Name: ' + project.Name + ', Owner Name: ' + project.Owner.Name);
}

Output:

Use inherited with sharing in Salesforce

Since we use the “with sharing“, the inherited class ApexInheritedSharing will run in the context of a current user, following the sharing rules and return only records owned by the current user.

Calling the Inherited Sharing class from “without sharing class“:

public without sharing class ApexWithSharing {
    @AuraEnabled(cacheable=true)
    public static List<Project__c> getProjectsInherited() {
        return ApexInheritedSharing.getProjects();
    }
}

When we call the inherited class “ApexInheritedSharing“, using the without sharing keyword, then it will display all the records in the context of the current user by overriding the permission rules.

Use the below anonymous code in the With Sharing class to execute it:

List<Project__c> projects = ApexWithSharing.getProjectsInherited();
for (Project__c project : projects) {
    System.debug('Project Name: ' + project.Name + ', Owner Name: ' + project.Owner.Name);
}

Output:

Ingherited with sharingin Salesforce Apex

Since we used the “without sharing” in the calling class, the inherited class overrides the sharing rules and returns all the records irrespective of the current user context.

So, this is how the Inherited sharing works in Salesforce Apex, where it inherits the sharing setting from the calling class.

Default Sharing or Omitted Sharing in Salesforce Apex

When we don’t mention any sharing keyword in the Apex class, such as “with” or “without” sharing, then it is called Default Sharing or Omitted Sharing.

This is a very important class sharing, as this is the most complicated and unpredictable sharing setting for the apex classes. In this, we don’t want to use the keyword like “Omitted” or “Default”, it’s just that, if you don’t use any sharing keyword, it takes the default.

The code of default or omitted apex class is as below:

public  class ProjectSharing {
    @AuraEnabled(cacheable=true)
     public static List<Project__c> getProjects(){
        return return [SELECT Name, Owner.Name FROM Project__c];
    }
}

Since no sharing keyword is defined, it will bypass the sharing rules and return all records to the current user.

Using Omitted sharing with Inherited Class in Salesforce Apex

It is always recommended to avoid omitted sharing, as it is not good for data security. There are some considerations that you should be aware of while using the omitted sharing with the inherited class.

  • If a class with “with sharing” is calling a method of a class with omitted sharing, which in turn calls a method of a class with inherited sharing, then it will run in with sharing mode, as the calling class is in with sharing mode and the omitted class is established as with sharing context.
  • If a class with “without sharing” is calling a method of a class with omitted sharing, which in turn calls a method of a class with inherited sharing, then it will run in without sharing mode, as the calling class is in without sharing mode and the omitted class is established as without sharing context.

This way, we can implement the sharing rules context in the Salesforce Apex class to restrict or allow users to access the records and the data in the Salesforce org.

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.