Skip to main content

SF-0294 · Scenario · Hard

Is there any other way we can enforce security apart from the "with sharing" keyword? Or How to enforce security to a specific method or lines of code instead of the whole class?

✓ Verified by Vikas Singhal · Last reviewed 5/17/2026

with sharing only enforces record-level access — it leaves field-level security (FLS) and object CRUD unenforced. To enforce security at finer granularity — a single SOQL query, a single DML, or a specific code path — Salesforce gives you several modern tools: WITH USER_MODE / WITH SYSTEM_MODE on SOQL/DML, Security.stripInaccessible(), the older WITH SECURITY_ENFORCED clause, and explicit Schema.sObjectType.X.isAccessible() / isUpdateable() / isCreateable() / isDeletable() checks. Each operates at a different scope so you can mix them.

WITH USER_MODE — the modern one-stop clause

Added in API v60+, WITH USER_MODE on a SOQL or DML statement enforces sharing, FLS, and CRUD as the running user — in one keyword. It’s the cleanest replacement for hand-rolled enforcement.

public without sharing class OrderService {
    public List<Order> userVisibleOrders() {
        // Enforces sharing + FLS + CRUD as the running user,
        // even though the class is 'without sharing'
        return [SELECT Id, OrderNumber, TotalAmount
                FROM Order
                WITH USER_MODE];
    }

    public void closeOrder(Id orderId) {
        Order o = new Order(Id = orderId, Status = 'Closed');
        update as user o;     // DML equivalent of USER_MODE
    }
}

as system is the opposite — explicit elevation. Both make intent obvious in the code.

Security.stripInaccessible() — sanitize records before/after DML

stripInaccessible(AccessType, records) removes fields and records the user can’t read/edit, returning a sanitized list. Useful when you accept a payload from an LWC and want to forward it to DML without exposing fields the user shouldn’t be able to write.

public without sharing class AccountUpdateService {
    public static void updateFromUi(List<Account> incoming) {
        SObjectAccessDecision decision =
            Security.stripInaccessible(AccessType.UPDATABLE, incoming);

        // decision.getRecords() now contains only fields the user can update
        update decision.getRecords();
    }
}

AccessType values: READABLE, CREATABLE, UPDATABLE, UPSERTABLE.

WITH SECURITY_ENFORCED — the older FLS clause

Pre-USER_MODE, WITH SECURITY_ENFORCED on SOQL enforced FLS and object CRUD on the queried fields. It throws an exception if any selected field is inaccessible, rather than silently stripping.

List<Contact> cs = [
    SELECT Id, Name, Email
    FROM Contact
    WITH SECURITY_ENFORCED
];

Use USER_MODE instead in new code — same effect, more flexible.

Explicit Schema.sObjectType checks

The lowest-level mechanism — used heavily before stripInaccessible and USER_MODE existed:

if (!Schema.sObjectType.Account.fields.AnnualRevenue.isUpdateable()) {
    throw new MyAppException('No update access on AnnualRevenue');
}
if (!Schema.sObjectType.Case.isCreateable()) {
    throw new MyAppException('No create access on Case');
}

Still relevant for one-off checks or for conditional UI logic in Apex helpers, but verbose for bulk operations.

How to pick the right tool per scope

ScopeTool
Whole class — record sharing onlywith sharing / without sharing / inherited sharing
Single SOQL — sharing + FLS + CRUDWITH USER_MODE
Single DML — sharing + FLS + CRUDas user / as system on insert/update/upsert/delete
Single SOQL — FLS + CRUD onlyWITH SECURITY_ENFORCED (legacy)
Bulk sanitize before DMLSecurity.stripInaccessible()
One field, conditional logicSchema.sObjectType.X.fields.Y.isUpdateable()
One object, conditional logicSchema.sObjectType.X.isCreateable() etc.

A combined example

public inherited sharing class CaseClosingService {

    public static void closeAndAudit(Id caseId, String reason) {
        // 1. Object CRUD check
        if (!Schema.sObjectType.Case.isUpdateable()) {
            throw new MyAppException('No update access on Case');
        }

        // 2. Read with full enforcement
        Case c = [SELECT Id, Status, OwnerId FROM Case WHERE Id = :caseId WITH USER_MODE];

        c.Status = 'Closed';
        c.Reason = reason;

        // 3. Strip any inaccessible fields the LWC might have sent
        SObjectAccessDecision d =
            Security.stripInaccessible(AccessType.UPDATABLE, new List<Case>{ c });

        // 4. DML in USER mode — sharing + FLS + CRUD
        update as user d.getRecords();
    }
}

Why interviewers ask this

Knowing only with sharing is the classic junior trap. Senior developers know with sharing is one of several tools, that FLS and CRUD need their own enforcement, and that the modern USER_MODE / stripInaccessible pattern is what Salesforce expects on AppExchange security reviews today.

Verified against: Apex Developer Guide — Enforcing Object and Field Permissions, WITH USER_MODE, and Sharing & Visibility Architect resources. Last reviewed 2026-05-17.