[SalesForce] How to provide access to Salesforce REST API to external application without providing them Integration user credentials

Our salesforce org needs to expose some functionality as a REST API class to an external app.
We created the apex class(@RestResource(urlMapping='')), now to provide access to the external app :

  • We created a new Integration User with limited access to profile and API enabled = true.
  • We provided the credentials of this user to external app.
  • We created a connected app and provided client_id and secret to external app.
  • We provide salesforce oauth URLs to external app.
  • External app uses Username Password oauth authentication flow with salesforce using these details to get access token.

We would like to explore a way without having need to create an Integration user and sharing this user's credentials.

How can this be achieved?

Best Answer

"Authentication without credentials" is fairly close to being a misnomer. By definition, if you want to authenticate a caller, you need some kind of credentials, and the best and most secure solution is to use a Salesforce user authenticated via OAuth.

There is another option that is suitable for specific situations, but is not a general-purpose replacement for credential-based authentication: a webhook. Webhooks are exposed to the open world and manually authenticate that inbound messages come from some client that knows a pre-shared secret. They do this by validating an HMAC signature (loosely, a cryptographically secure hash of the message content plus some pre-shared secret).

The webhook's Apex class is exposed to the world as an unauthenticated REST service on a Force.com Site.

Webhooks thus provide message integrity checks and a species of authentication without sharing user credentials. However, they come with some significant limitations.

  • If there's more than one caller using the same pre-shared secret, you can't tell them apart, and there's no audit trail of what client made what request.
  • You have to write more code to achieve the authentication on both the sending and the receiving end.
  • It is easy to make mistakes in crypto code that reduce or destroy the security of your solution.
  • Your receiving user will be the Site Guest User, under whose context the Apex class runs. This imposes a lot of permissions-based limitations on what you can do, and may conflict with other things you hope to run on that Site.

In most situations, I would encourage using an integration user.

An integration user should always authenticate via OAuth and store a refresh token (unless using the JWT flow, in which case it should store a username and certificate). The remote system should not store a username and password. However, authentication to Salesforce always requires that a user exist in the target system.

Related Topic