1

I created a Permission Set and made one change on it: System Permission: "View All Records"

I gave it to a User with Standard Profile.

When I tested as this user, it could Update and Delete records of Account, Lead, etc. This doesn't work for me. I want Read-only across the board.

So I changed the User to "Minimal" profile, where all Object Permissions are set to "No access". It still has the Permission Set.

Now, when I login as the User, objects do not appear in the Wafer (object explorer).

What else do I need to configure to truly have Read only to all records in Salesforce?

3 Answers 3

2

View All Records doesn't include metadata (things found in Setup). Add View All Users to allow them to see users.

6
  • Thanks @sfdcfox for your reply. I ran another test. I see now, on the Permission Set: A) I need to check the Available and Visible boxes; B) I need to check "Read Access" on all Fields; C) It does not appear I need to check boxes for all the Record Types to view them all (correct me if I'm wrong). Commented Apr 7 at 17:57
  • Also, 2 questions: 1) do you have a script to do A and B across 600+ objects (including Managed Package objects)? 2) I need to give this integration user to my AWS pro, so he can pull all SF data into a data lake... I chose a standard Salesforce license bc it's easier for me to test. That said, will an SF Integration User License with SF API Only System Integrations profile somehow make my work easier? And if I go that route: A) how to test to make sure he can view all data across all objects, and B) Is it responsible to use the SF API Only System Integrations, given end of life in 2026? Commented Apr 7 at 19:05
  • @RyanMcNeely For (a) and (b), you'll probably want a queueable/batchable to handle this to deal with governor limits. As Peter said, View All Data covers all normal objects (standard and custom, not metadata), so you'd only have to worry about fields. This can be scripted in Apex, Visualforce, LWC, etc. The new integration model replaces the older API Only System Integrations model (see Client Credentials Flow). I'd use that instead.
    – sfdcfox
    Commented Apr 7 at 20:59
  • Thanks @sfdcfox, I tried creating the Connected App today, but got stuck on OAuth Scope. I believe this is where I'll define object and record access. Which scope should I focus on? help.salesforce.com/s/… Commented Apr 9 at 1:46
  • @RyanMcNeely Not sure what your specific use case is, but you could probably just do "full". The user's profile permissions will still prevent them from modifying data.
    – sfdcfox
    Commented Apr 9 at 2:10
2

Given that System "View All Data" implies/grants/gives "Read" and "View All" access (in object permissions)...

I suspect why your test user cant see object(s) in the wafer might be because those objects still need a "Tab" defined, and defining a Tab for an sobject is what makes it eligible to appear in that ui.

4
  • Thanks for your reply Peter, I just ran a test. Before adding <System:View All Data> to the PermSet, in the Object Settings of the PermSet, I see "No access" for all Objects. After adding <System:View All Data> to the PermSet, I see "Read" and "View All" for all objects. Do you agree now that to have View All Data is to also have Read and View All at the Object Setting level? Commented Apr 7 at 17:37
  • Thank you Ryan for correcting me on that part. You are correct (I just now ran a similar test on Profile meta and your point holds true.) I've edited my answer with that in mind, with another possible explanation. Commented Apr 8 at 18:28
  • I agree with your answer. And also, I found that FSL needs to be turned on, for which I'll need to write a batch job to cover all 400-600 objects. I also found that Record Type on the Object setting can be false, but I still have access to those records, I guess because of "View All Data". Commented Apr 9 at 16:13
  • Depending on your visibility needs, Id recommend also looking at the objects’ OWD, Sharing Rules, and any other sharing tools covered in the Who Sees What series Commented Apr 10 at 19:37
0

Thanks sfdcfox and peter for putting me on the right path.

For each FLS on a particular Permission Set, there's a FieldPermissions record in the background. This script went through over 500 objects in my org, setting every settable field to Read. Combined with System Settings: View All Data and API access, and this Permission Set I created for him, my User can pull all needed data into an external data lake.

public with sharing class PermissionSetUpdateBatch implements Database.Stateful, Database.Batchable<String> {
private String INTEGRATION_BOT_PERMSET_ID = [SELECT Id 
                                             FROM PermissionSet 
                                             WHERE Label = 'Integration Bot View All Records'
                                             LIMIT 1].Id;
private Map<String, Schema.SObjectType> globalDescribe = Schema.getGlobalDescribe();
private List<FieldPermissions> fieldPermissionsList = [SELECT Id, Field 
                                                       FROM FieldPermissions 
                                                       WHERE ParentID =: INTEGRATION_BOT_PERMSET_ID 
                                                       AND PermissionsRead = true];
private Set<String> fieldsWithPermReadTrue = new Set<String>();

public Iterable<String> start(Database.BatchableContext context) {
    System.debug('>>> INTEGRATION_BOT_PERMSET_ID: ' + INTEGRATION_BOT_PERMSET_ID);
    System.debug('>>> fieldPermissionsList: ' + fieldPermissionsList);
    
    for (FieldPermissions fp : fieldPermissionsList) {
        fieldsWithPermReadTrue.add(fp.Field);
    }
    System.debug('>>> fieldsWithPermReadTrue: ' + fieldsWithPermReadTrue);

    List<String> objApiNames;
    System.debug('>>> objApiNames: ' + objApiNames);
    if(Test.isRunningTest()){
        objApiNames = new List<String>();
        objApiNames.add('order');
    } else {
        objApiNames = new List<String>(globalDescribe.keySet());
    }
    return objApiNames;
}

public void execute(Database.BatchableContext bc, List<String> objectApiNames){
    List<FieldPermissions> fieldPermissionsForInsert = new List<FieldPermissions>();
    
    for (String objectApiName : objectApiNames) { // loop all SObject
        //EntityDefinition ed = (EntityDefinition)record;
        System.debug('------- objectApiName: ' + objectApiName);

        // get the describe for each individual object
        Schema.SObjectType sobjectType = globalDescribe.get(objectApiName);
        System.debug('------- sobjectType: ' + sobjectType);
        Schema.DescribeSObjectResult objectDescribe = sobjectType.getDescribe();
        
        Map<String, Schema.SObjectField> objectFields = objectDescribe.fields.getMap();

        for (String fieldApiName : objectFields.keySet()) { // loop all fields per object
            System.debug('>>>> fieldApiName: ' + fieldApiName);
            Schema.SObjectField sobjectField = objectFields.get(fieldApiName);
            String objectDotField = objectApiName + '.' + fieldApiName;
            
            if (!fieldsWithPermReadTrue.contains(objectDotField)) {
                 FieldPermissions newFP = new FieldPermissions();
                 newFP.ParentId = INTEGRATION_BOT_PERMSET_ID;
                 newFP.SObjectType = objectApiName;
                 newFP.Field = objectDotField;
                 newFP.PermissionsRead = true;
                 fieldPermissionsForInsert.add(newFP);
            }
        }
    }
    Database.insert(fieldPermissionsForInsert, false);    
}

public void finish(Database.BatchableContext bc){
    // execute any post-processing operations
}

}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .