Exception when trying to authenticate with OAuth 2.0 Web Server Flow for Web App Integration
My understanding is for the "OAuth 2.0 Web Server Flow for Web App Integration" you only need the client_id and the client_secret to get an OAuth Token. We tried that like this:
$this->restforce = new Restforce(
$salesforce_credentials['client_id'],
$salesforce_credentials['client_secret'],
NULL,
NULL,
NULL,
$salesforce_credentials['api_version'],
$salesforce_credentials['instance_url'],
);
That throws this exception:
PHP Fatal error: Uncaught EventFarm\Restforce\RestforceException: Restforce needs either an OAuthToken or User/PW combo to start authenticate in vendor/eventfarm/restforcephp/src/RestforceException.php:15
Stack trace:
#0 vendor/eventfarm/restforcephp/src/Restforce.php(48): EventFarm\Restforce\RestforceException::minimumRequiredFieldsNotMet()
#1 salesforce/SalesforceApi.php(21): EventFarm\Restforce\Restforce->__construct()
#2 foo.php(19): Salesforce\SalesforceApi->getRestforceClient()
#3 [internal function]: test_function()
But, if we take out this check in vendor/eventfarm/restforcephp/src/Restforce.php, then everything works fine:
if ($accessToken === null && $username === null && $password === null) {
throw RestforceException::minimumRequiredFieldsNotMet();
}
You don't need to start with an access token to use this flow to authenticate with Salesforce, so I'm not sure why that parameter is required.
I am in a similar situation. I feel that we could change the check to something different, such as:
if (!$this->minimumAuthRequiredFieldsAreMet($clientId, $clientSecret, $accessToken, $username, $password)) {
throw RestforceException::minimumRequiredFieldsNotMet();
}
(...)
private function minimumAuthRequiredFieldsAreMet($clientId, $clientSecret, $accessToken, $username, $password)
{
return $this->requiredFieldsForOauthAccessTokenAreMet($accessToken)
|| $this->requiredFieldsForOauthCredentialsAreMet($clientId, $clientSecret, $accessToken)
|| $this->requiredFieldsForPasswordCredentialsAreMet($username, $password);
}
private function requiredFieldsForOauthAccessTokenAreMet($accessToken)
{
return $accessToken !== null;
}
private function requiredFieldsForOauthCredentialsAreMet($clientId, $clientSecret, $accessToken)
{
return $accessToken === null && ($clientId !== null && $clientSecret !== null);
}
private function requiredFieldsForPasswordCredentialsAreMet()
{
return $username !== null && $password !== null;
}
We can see that OAuthRestClient is capable of getNewToken provide we have id and secret.
An alternative would be to turn OAuthRestClient.getOAuthAccessToken() into a public method. Then, we could do:
$oauthRestClient = new OAuthRestClient(
new SalesforceRestClient(
new GuzzleRestClient(getenv('REST_ENDPOINT')),
self::DEFAULT_API_VERSION
),
new GuzzleRestClient(getenv('REST_ENDPOINT')),
getenv('REST_CLIENT_ID'),
getenv('REST_CLIENT_SECRET'),
);
return new Restforce(
getenv('REST_CLIENT_ID'),
getenv('REST_CLIENT_SECRET'),
$oauthRestClient->getOAuthAccessToken(),
(...)
);
But there is unnecessary repetition, as the first approach would handle everything and prevent duplicate creation of guzzle clients, as we cannot pass OAuthRestClient, that will be created again inside Restforce.
This is a great salesforce API library.
I am happy to create a PR either option is preferred by the author.