In the Salesforce Winter Release Review, Salesforce announced that one can authenticate with the API using only a client id and client secret from the corresponding “Connected App” and the API requests will run as a specified user using the new “Client Credentials” OAuth2 flow. That is very useful for system-to-system integrations that I previously would typically use the “Username / Password” OAuth2 flow for. The “Username / Password” flow requires one to also supply the username, password, and security token as part of the API authentication request in addition to the Client Id and Client Secret.
Naturally, I wanted to research this new “Client Credentials” OAuth2 flow and see what it’s like.
Client Credentials Setup
Primary setup steps
- Create Integration Profile For API Only User
- Create Integration User
- Create “Client Credentials” Connected App
Create Integration Profile For API Only User
First, an Integration profile needs to be created with the API Only permission chosen so that the integration user that uses this will only have API access. This is a requirement for the “Client Credentials” connected app later.
In Salesforce Setup, open profiles, click New and for the “Existing Profile”, choose “Standard User”. For the “Profile Name”, choose something appropriate such as “<System> Integration”. Mine will be named “Client Creds Test”. Click Save.
After the profile is created, click the Edit button. Next, under Administrative Permission, check the “API Enabled” checkbox if it’s unchecked. Check the “Api Only User” checkbox. Click Save. The other permissions can be updated later.
Note: The API Only User permission is only available for “Enterprise Edition” and above orgs and sandboxes. It is not available for “Developer Edition” non-sandbox orgs. I discovered this when trying to view this in a Developer Edition preview org.
Now, continue with creating the Integration User.
Create Integration User
Now that the Integration Profile is available, let’s create the integration User. In Setup, search for “Users” and click the “Users” link. Next click the “New User” button. Fill in the following fields
- First Name – The system name that is integrating with Salesforce.
- Last Name – “Integration”. I prefer that the first and last name comprise the system name and the word “integration” so one can easily identify what the user is for.
- Email – Ideally, this is a distribution email so a team can monitor it.
- User License – Typically “Salesforce” but use the right one for the profile chosen.
- Profile – The one created in the previous step.
Click Save.
Now the user is created and the connected app can be created.
Create “Client Credentials” Connected App
In Setup, search for “App” and open the “App Manager” link.
Click “New Connected App”. Enter the following:
- Connected App Name – The name should contain the name of the system and “Integration” like “<system> Integration”. if my system is named “Acme” the connected app should be named “Acme Integration”.
- API Name – Let Salesforce populate it based on the Connected App Name.
- Contact Email – Ideally a distribution email containing your team that will be maintaining this.
- Enable OAuth Settings – Check and then the following settings appear.
- Callback URL – Enter “https://localhost”
- Selected OAuth Scopes – Choose “Manage user data via APIs (api)”.
- Enable Client Credentials Flow – Check the checkbox and click Ok to the alert message.
Click “Save” and then click “Continue”.
Now the connected app is created but one has to go elsewhere to configure the running user which is absurd.
Next, click the “Manage” button and then click “Edit Policies”. Scroll Down and under “Client Credentials Flow”, click the hour glass button, choose the integration user previously created, and click Save.
Now one can authenticate with the API using the token endpoint.
Resources
- Configure a Connected App for OAuth 2.0 Client Credentials Flow
- OAuth 2.0 Client Credentials Flow for Server-to-Server Integration
API Authentication Via Postman
One very nice thing about this OAuth flow is one only needs the Consumer Key and Consumer Secret from the connected app to use as the “Client Id” and “Client Secret” in the API’s authentication request body without the username, password, and security token.
One make’s a “Post” HTTP Request to the <my_domain>/services/oauth2/token endpoint where <my_domain> is your Salesforce environment’s My domain. One can also use “http://test.salesforce.com” for sandboxes and “https://login.salesforce.com” for production and non-sandbox orgs like “Developer Edition” orgs.
Post Key / Values in x-www-form-urlencoded format
Key | Value | Notes |
grant_type | client_credentials | This tells Salesforce the grant type used. The “client_credentials” is new. |
client_id | The Consumer Key value from the connected app. | |
client_secret | The Consumer Secret value from the connected app |
The response is a JSON packet containing the access_token, instance_url, and other information. The access_token and instance_url are the important values. The access_token is used in subsequent API requests to do stuff within Salesforce. The instance_url is used in the domain in subsequent API requests so one doesn’t have to hard-code the different Salesforce environment domains in the client application.
Findings
- One can only use an API Only user for the integration. That means the user can’t login through the browser which is great for system-to-system integrations.
- The API Only user permission is only accessible from Enterprise, Unlimited, and sandbox orgs. I couldn’t use a “Developer Edition” non-sandbox org for this. One can create an “Enterprise Edition” preview org to test this which is what was done.
- The Salesforce setup is almost identical to that used for a dedicated integration user with the “Username / Password” OAuth2 flow.
- One does not share the username, password, and security token with the client application so the client application does not know which Salesforce user it’s running as unless someone tells them.
- The authentication request is much simpler since one specifies the grant type using “client_credentials” and provides the client id and client secret. That means the client application only needs to have the client id and client secret. Salesforce says this is more secure but I’m not sure since the username / password flow required one to have 3 additional inputs. I suppose it’s more secure because the client doesn’t have to store those securely anymore but I’m unsure. The Client Id and Client Secret still need to be stored securely. If someone can explain how this is more secure, that would be appreciated.
- One can still control the permissions the integration user has via the profile and permission set(s) it uses. I thought this would run as system at first but that’s not the case.
Recommendation
One should use the new “Client Credentials” OAuth2 flow for system-to-system integrations as the default choice over the “Username / Password” flow. One could also look into the “JWT” flow but that requires certification exchange and other additional setup. What do you think?