When working with integrations, many applications need to connect to Salesforce and invoke REST APIs to access data and perform business processes. This blog post describes the optimal approach to connecting these applications with Salesforce using a dedicated user for each application. This ensures that each application only has access to the data and operations that it needs, and nothing more, while providing distinct auditability and traceability of requests from each application.

This is achieved in three easy steps:

  1. Define the integration user: Connect each application to Salesforce using a dedicated integration user using the Salesforce Integration user license and the Minimum Access – API Only Integrations profile.
  2. Specify the authentication flow: Authenticate each application using the OAuth client credentials flow, which is intended for server-to-server connections.
  3. Authorize your user: Follow the principle of least privilege and limit each application to only have access to the data and operations that the application needs using permissions sets with the Salesforce API Integration permission set license (PSL).

Integrating with the Salesforce integration user

The Salesforce Integration user license provides a cost-effective approach to integrating each of your applications with Salesforce using a dedicated user.  Employing a dedicated user for each application enables you to enforce access scoped to each application, and trace or audit requests for each application. 

The Salesforce Integration user license makes the Minimum Access – API Only Integrations profile and the Salesforce API Integration permission set license (PSL) available in your org.

  • The Minimum Access – API Only Integrations profile both enables API access and restricts the user to only API access, and these permissions cannot be edited
  • The Salesforce API Integration PSL entitles the Salesforce Integration user license with the same user and object permissions available as in the System Administrator profile in the standard Salesforce user license

Enterprise Edition, Unlimited Edition, and Performance Edition orgs are automatically provisioned with five Salesforce Integration user licenses, and additional licenses can be purchased. You can view the number of Salesforce Integration user licenses and Salesforce API Integration permission set licenses your org has on the Company Information page.

Image of Setup / Company Information page show user licenses and permission set licenses

Minimum permissions in the Minimum Access – API Only Integrations profile

The Integration user license follows the Salesforce recommendation that user access permissions should be managed by permission sets and permissions set groups. See the blog, Admin Best Practises for User Management, for more information on this approach.

The Minimum Access – API Only Integrations profile is based on the existing Minimum Access – Salesforce profile, and only provides the absolute minimum permissions needed.  The profile should only be used to manage defaults (including record types), page layout assignments, login hours, and IP ranges. While the profile both enables API access (“API Enabled”) and restricts access to API interactions (“Api Only User”), these permissions cannot be edited in the profile. 

Other permissions, such as user permissions, object and field permissions, and more, should be managed using permission sets and permission set groups as discussed below.

The screenshot below shows a dedicated integration user for an ERP application to integrate with Salesforce, with the Integration user license and Minimum Access – API Only Integrations profile assigned.

Users page showing the creation of the ERP integration user with the Salesforce Integration user license and Salesforce API Only System Integrations profile assigned.

Prior to the Spring ’24 release, the Integration user license made the Salesforce API Only System Integrations profile available. There was a known issue with this profile incorrectly providing CRUD permissions to custom objects. The Spring ’24 release addresses this issue with the new Minimum Access – API Only Integrations profile and only this new profile will be available in newly provisioned orgs. While the API Only Systems Integration profile remains available in existing orgs provisioned prior to Spring ’24, we recommend that you plan to move your integration users to this new profile.

Authentication using OAuth Client Credentials Flow

When you are planning to build out a server-to-server integration, one of the most important things to consider is what authentication flow you use to authenticate your application with Salesforce. In this example, we are going to use the client credentials flow, which is intended for server-to-server connections.

At a high level, the client credentials flow uses the client ID and secret of a Salesforce-connected app to authenticate to your Salesforce org. The authentication produces an access token that is on behalf of the integration user you configure in the connected app (discussed more below). This flow does not produce a refresh token, it is assumed that the client can simply request a new access token using the client ID and client secret once their existing access token expires.

The client credentials flow is a good fit when the following statements are true.

  • The integration has no end-user interaction during the authentication process
    • It is a headless integration between Salesforce and another service
  • The integration always runs as the same integration user in Salesforce
  • The external service is capable of keeping secrets and is trusted to do so

Point three above is incredibly important. As we said, the client credentials flow uses the client ID and client secret to authenticate to your org. You can think of this as a rough equivalent of a username and password. Your client must be capable of keeping the client ID and client secret safe, but if it is not able to keep these secrets, then you cannot use this flow.

The screenshot below shows the connected app for our ERP integration.

App Manager page showing the creation of the ERP Integration connected app.

When setting up the client credentials flow, you must configure the connected app’s policies to enable the client credentials flow. This is required even if the app was installed from the Salesforce AppExchange. Salesforce requires this for security reasons — we want to ensure that the admin of the org has explicitly enabled the flow for their org.  

To enable your app for the client credentials flow, go to the Manage view of the connected app. Click Edit, change the permitted user policy to Admin Pre-Approved, and specify  Run-As User for the client credentials flow. Click Save. These steps enable the flow for your org and app. 

The run-as user you specified is the Salesforce user that the client credentials flow retrieves a token on behalf of. All actions taken by the integration (client) using the client credentials flow run as this user in Salesforce, and its data access, and CRUD rights are the same as that user.

This is why using the new integration user is so important. With an integration like the client credentials flow, each integration user should map to a single integrating system for auditability and traceability. It is also important that each integration’s data access be scoped down to only what is needed. 

The screenshot below shows editing the ERP Integration connected app to specify the Admin Pre-Approved permitted user policy and ERP integration user as the run-as user for the client credentials flow.

Connected App page showing details of the ERP Integration connected app, including specifying the ERP integration user as the run-as user for the client credentials flow.

Finally, go to the permission set related list, and add the permission set that belongs to your integration user.

By setting the Apps Permitted User Policy to Admin Pre-Approved, you lock the connected app to only allow a specific set of users. By adding either a profile or a permission set to the connected app, you enable a user or a set of users to use the connected app. Like with the integration user, a best practice with the Salesforce client credentials flow is to have a single app per integration and to only enable a single user (the integration user) via a permission set to use the app. This ensures auditability and traceability, and in the case of a rogue actor, it allows you to rotate the client ID and client secret and only affect a single integration.

Now that you have configured a connected app for the client credentials flow, it is time to get an OAuth token using the client credentials flow. You can read more about the implementation of the flow in the documentation. If you are using a pre-built integration, often all you need to do is provide the URL for the token endpoint, which is <mydomain>.my.salesforce.com/services/oauth2/token, and the connected app’s client ID and client secret. Please note that if you are trying to integrate with a Salesforce Experience Cloud site, you simply use the same URL above, but instead use the Experience Cloud domain.

If you are developing the integration yourself, all the client has to do is POST the client ID and client secret to the Salesforce token endpoint. You can see an example of this request below.

When the request is successful, the response is the following:

JWT-Based Access Tokens

Salesforce now has the option to issue JWT-based access tokens or our classic opaque access tokens. Which one you choose to use is up to you and your integration/security needs. However, this choice can lead to design considerations for refresh logic.

In general, the best practice, especially with opaque access tokens, is simply to try to use them. If they fail due to a 401, attempt a refresh (in this case simply by running the client credentials flow again). If the refresh is successful, use the new token. If the refresh is not successful, throw an error so that the integration owner knows there is a problem. This process works universally with JWT-based access tokens and opaque access tokens.

If you want to be more efficient and you are using the new JWT-based access tokens, you can locally inspect the access token for its exp claim. JWT access tokens have hard timeouts, and this allows you to inspect the token before making a call to the Salesforce API to check if it should still be valid. If not, you can attempt to refresh first before making the call. In general, though, it is a good idea to implement the logic described above for opaque tokens as the org signing key can be rotated at any time, effectively invalidating your JWT before its expires_at claim.

Now that we have taken care of authentication, let’s look at authorization.

Authorization using Permission Sets

The final step is to configure the integration’s access to data and operations. Following the principle of least privilege, each integration should only have access to the data and operations that it needs, and nothing more. This access is managed using permission sets and permission set groups.

The Salesforce API Integration permission set license (PSL) entitles the Salesforce Integration user license with the same user and object permissions available in the System Administrator profile in the standard Salesforce user license. It is important to understand that the API Integration PSL does not grant these permissions to a specific user with the Salesforce Integration user license — it only entitles the user to these permissions.

The image below shows the relationship between all the configurations using our ERP integration example:

Image showing the relationships between all the configurations described in this blog

To grant permissions to the integration user, first create a new permission set with the API Integration PSL. Second, in the permission set, enable the permissions you wish to grant to the integration user — noting that you can only grant the permissions entitled by the API Integration PSL. Finally, assign the permission set to the integration user.

You should create a dedicated permission set for each integration and assign that permission set to the integration user associated with that integration. This ensures that each integration is only granted access to the absolute minimum set of data and operations that it needs, and nothing more.

The screenshot below shows the process for creating a dedicated permission set for the ERP integration with the API Integration PSL assigned.

Permission Sets page showing the creation of the ERP Integration permission set with the Salesforce API Integration PSL assigned.

The ERP Integration permission set can then be configured to provide access to the data and operations the ERP integration needs. Finally, the ERP Integration permission set is assigned to the ERP integration user as shown in the screenshot below.

ERP Integration Perm Set page showing the ERP Integration permission set assigned to the ERP integration user.

Conclusion

We recommend that each third-party application that integrates with the Salesforce REST APIs follow the approach that we described in this post. That is: authenticate using a dedicated connected app and run requests using a dedicated integration user assigned a dedicated permission set. This ensures that each application only has access to the data and operations that it needs, and nothing more while providing distinct auditability and traceability of requests from each application.

The Salesforce Integration user license is a cost-effective approach to giving each application its own dedicated user. When used with the OAuth client credentials flow and permission sets, this license type provides both an easy and powerful mechanism to authenticate and authorize each application’s access to data and operations in your Salesforce org.

Further Resources

About the authors

Samuel Rosen is Director of Product Management, Salesforce Identity. He is responsible for Connected Apps, Identity Protocol support, and Salesforce’s larger Customer Identity and Access Management Strategy. Follow him on LinkedIn.

Jeremy Westerman is Director of Product Management, Salesforce APIs. He is responsible for Salesforce APIs that access data on the core Salesforce Platform. Follow him on LinkedIn and the Trailblazer Community.

Get the latest Salesforce Developer blog posts and podcast episodes via Slack or RSS.

Add to Slack Subscribe to RSS