Update Function Permissions

Salesforce permission sets are used to control which org data Salesforce Functions can access. When you deploy your function, make sure your function is associated with a permission set that has the correct data permissions.

All deployed functions invoked by an org use the Functions permission set in that org when making data requests. This permission set is automatically created when you connect your Dev Hub org with Salesforce Functions. Update the permission set to set data permissions specific to your function.

Instead of assigning all permissions for all Salesforce Functions to the Functions permission set, you can use session-based permission sets to scope permissions to a specific function.

Note

To modify the data permissions for your function, update the Functions permission set in the org that invokes the function. You can update the permission set using the Salesforce UI, or add a Functions.permissionset-meta.xml to your DX project’s force-app/main/default/permissionsets folder, with the desired data permissions. For example, give your function read and create access to the Account object in your org with the following Functions.permissionset-meta.xml:

1<?xml version="1.0" encoding="UTF-8"?>
2<PermissionSet xmlns="http://soap.sforce.com/2006/04/metadata">
3    <hasActivationRequired>true</hasActivationRequired>
4    <label>Functions</label>
5    <objectPermissions>
6        <allowCreate>true</allowCreate>
7        <allowDelete>false</allowDelete>
8        <allowEdit>true</allowEdit>
9        <allowRead>true</allowRead>
10        <modifyAllRecords>false</modifyAllRecords>
11        <object>Account</object>
12        <viewAllRecords>false</viewAllRecords>
13    </objectPermissions>
14</PermissionSet>

After you update the Functions permission set in your DX project, deploy your changes to your org. When using scratch orgs, use the sf project deploy start command to deploy permission set changes (and other project-side changes) to your org. If you’re collaborating with other developers and sharing an org and compute environment, make sure to merge your permissions changes with any changes your team has already pushed to the shared org. Retrieve changes to your project with sf project retrieve start first if necessary. For details on syncing project and scratch org changes, see Retrieve Source from the Scratch Org to Your Project.

If you’re deploying your functions to a sandbox org, merge and push your permission changes using the same sf commands: sf project deploy start and sf project retrieve start. For more information on syncing project and sandbox org changes, see Develop Functions Using Sandbox Orgs.

Note

For more information on Salesforce permission sets, see Permission Sets Overview.

Use Permission Sets and Local Invocation 

When invoking a locally running function against a scratch org using sf run function start, the function uses the permissions of the current user, rather than the Functions permission set. The default scratch org user has System Admin privileges, but functions are called by the Cloud Integration User profile. Run your functions locally with a dedicated scratch org user with the minimum access to better test for real-world conditions.

Create a scratch org user using the Minimum Access - Salesforce profile. Create a permission set that provides the same object access permissions that your Functions permission set has, and apply this permission set to the new user. For more information on creating scratch org users, see Scratch Org Users.

Use Apex Invocation and Permissions 

From a permissions perspective, Apex code that invokes Salesforce Functions is no different than other Apex code. The code runs in system mode, as described in Understanding Describe Information Permissions. Functions invoked asynchronously with Apex work similarly. After the function executes, the Apex callback runs in system mode as the user that invoked the function.

Apex invocation can only invoke functions that have been deployed to a compute environment that is associated with the org the Apex code is running in. Apex code that invokes functions, like any Apex code, is considered “trusted code” in a given org, deployed to that org by someone that understands the security and permission requirements of that org.

Salesforce provides additional layers of permissions and security around who can execute Apex code, such as Author Apex permissions and Apex class security. Apply class security to your Apex code that invokes Salesforce Functions so only certain users can execute those classes. See Salesforce Help: How Does Apex Class Security Work? for more information on Apex class security.

Set Deployed Function Permissions 

When a deployed function is invoked, the function runs as the Cloud Integration User profile when making requests back to the org, not as the org user that invoked the function. Any data access permissions on the invoking user must work for the Cloud Integration User as well.

Data requests are checked against the Functions permission set. Set the object permissions in the Functions permission set to match the object permissions for the users that invoke the function. For example, add ViewAllRecords and ModifyAllRecords permissions if the function must view or modify objects.

If you encounter an error trying to access certain objects, check the license for the Cloud Integration User profile to verify that the user who runs functions can access the objects needed. Even when you define the access in the Functions permissions metadata file (Functions.permissionset-meta.xml), the license must also allow access to the objects.

To insert, update, or delete records of an object from a function, return record data in the function response and perform the DML operation in the function’s Apex callback. This approach runs Apex as the invoking user in system mode.

Note

See Give Users Access to Data for more details on setting data access permissions in your org.

Use Session-Based Permission Sets 

Users with the Functions permission set assigned can run any function in their org. You can also create individual permission sets for specific functions. These permission sets can be activated directly from the function code while the function executes with a session-based permission set.

Update Permissions for Functions Permission Set 

To create and use a session-based permission set, first update the existing Functions permission set so it can manage the individual function permission sets.

  1. From Setup, in the Quick Find box, enter Permission Sets, and then select Permission Sets.
  2. Click the Functions permission set and go to System Permissions.
  3. Click Edit and select Manage Session Permission Set Activations.
  4. Click Save.

Create a New Session-Based Permission Set 

Create a permission set to provide permissions when needed, like during invocation.

  1. From Setup, in the Quick Find box, enter Permission Sets, and then select Permission Sets.
  2. Click New and give the permission set a name specific to its associated function.
  3. Select Session Activation Required.
  4. Add any permissions to this permission set your function needs for execution, like Accounts in Object Settings if your function needs access to Account objects.
  5. Click Save.

Assign a Session-Based Permission Set to the Cloud Integration User 

The Cloud Integration User profile is what your Salesforce Functions use to make API calls on behalf of the function. You can’t assign the Cloud Integration User to a permission set in the Salesforce UI, so this step must be done on the command line.

Make sure you’re logged in to your org via the Salesforce CLI and use SOQL to query the User object to find the username for the Cloud Integration User profile.

1sf data query --query "SELECT Id, UserName from User WHERE username like 'cloud@00d%' LIMIT 10"
2ID   USERNAME
3---------------------
4005RO000000HiuWYAS cloud@00dro0000008boa2ay
5Total number of records retrieved: 1.
6Querying Data... done

Copy the username from the output (the one with cloud@ at the beginning) and use it to assign the session-based permission set to the Cloud Integration User.

1sf org assign permset --name SessionPermFunction --on-behalf-of cloud@00dro0000008boa2ay
2=== Permsets Assigned
3
4 Username                 Permission Set Assignment
5 ──────────────────────── ─────────────────────────
6cloud@00dro0000008boa2ay  SessionPermFunctions

Activate and Deactivate a Session-Based Permission Set in Function Code 

To assign a session-based permission set to the Cloud Integration User profile, you have to use the Salesforce REST API to make a request to activate it. Add this request in your function code.

Activate Session-Based Permission Set 

In Node.js with JavaScript:

1const { accessToken, baseUrl, apiVersion } = context.org.dataApi;
2const authHeaders = {
3Authorization: Bearer ${accessToken}
4};
5const apiUrl = ${baseUrl}/services/data/v${apiVersion};
6const { statusCode: statusCodeJob, body: bodyJob } = await request(
7${apiUrl}/actions/standard/activateSessionPermSet,
8{
9    method: "POST",
10    headers: {
11    "Content-Type": "application/json",
12    ...authHeaders
13    },
14    body: JSON.stringify({
15    inputs: [
16        {
17        PermSetName: "SessionPermFunctions"
18        }
19    ]
20    })
21}
22);
23const createJobResponse = await bodyJob.json();
24if (statusCodeJob !== 200) {
25logger.error(JSON.stringify(createJobResponse));
26throw new Error(Session Permset Activation failed);
27}
28logger.info(
29* Permset Activation *** :  + JSON.stringify(createJobResponse)
30);

Deactivate Session-Based Permission Set 

Add the deactivation code to your function to make sure the session-based permission set isn’t active for the next invocation.

In Node.js with JavaScript:

1const { statusCode: statusCodeJob2, body: bodyJob2 } = await request(
2  `${apiUrl}/actions/standard/deactivateSessionPermSet`,
3  {
4    method: "POST",
5    headers: {
6      "Content-Type": "application/json",
7      ...authHeaders,
8    },
9    body: JSON.stringify({
10      inputs: [
11        {
12          PermSetName: "SessionPermFunctions",
13        },
14      ],
15    }),
16  },
17);
18const createJobResponse2 = await bodyJob2.json();
19if (statusCodeJob2 !== 200) {
20  logger.error(JSON.stringify(createJobResponse2));
21  throw new Error(`Session Permset DeActivation failed`);
22}
23logger.info(`******* Permset Deactivation ******** : ` + JSON.stringify(createJobResponse2));

In Java:

1public class MyFunctonResponseHandler implements functions.FunctionCallback {
2    public void handleResult(FunctionInvocationStatus status) {
3        // Check status.getStatus() for error handling
4        // ...
5        // Activate the Function Permission Set
6        HttpRequest req = new HttpRequest();
7        req.setEndpoint(req.setEndpoint(Url.getOrgDomainUrl().toExternalForm()+
8            '/services/data/v49.0/actions/standard/activateSessionPermSet');
9        req.setMethod('POST');
10        req.setHeader('Content-Type', 'application/json');
11        req.setBody('{ "inputs" : [ { "PermSetName" : "HelloWorldPermissions"} ] }');
12        HTTPResponse res = new Http().send(req);
13        // All good store the response (client in this case using CDC to monitor)
14        insert new Widget__c(
15            SomeCalculatedInfo__c = status.getResponse(),
16            CalcContext__c = status.getInnvocationId()));
17    }
18}

Product Retirement Announcement

Salesforce Functions is no longer available for purchase or renewal. To preserve the capabilities that Salesforce Functions provided to your org, deploy an alternative solution before your existing order term ends. See Salesforce Functions Retirement for more information on migrating your functions. Contact your Salesforce Account Executive for more information on Heroku.