Salesforce REST API, OAuth, and Laravel
April 9, 2021
We have recently been working with a client that is using Salesforce for their CRM + Inventory Systems. While the solution works well, they have some specific reporting needs that are not easily possible within Salesforce.
In order to generate the reports / exports per their requirements, we need to connect to the Salesforce REST API to grab the data.
The reporting app is a basic Laravel project. We did some exploring for SDKs and Packages, but in the end decided it was simple enough to authenticate via OAuth using a standard Guzzle Client.
In order to Authenticate, we are using the standard Username + Password oAuth Flow. You can find instructions at that link on how to enable your Connected App and OAuth Settings.
Once we have all of those settings, let's define them in a couple of variables.
** You will note we are grabbing these values from a config file named "anvil". This just happens to be the name of the app we are working with, so feel free to store and retrieve these from the config file / pattern of your choice*
$apiCredentials = [ 'client_id' => config('anvil.anvil_id'), 'client_secret' => config('anvil.anvil_secret'), 'security_token' => config('anvil.anvil_token'), ]; $userCredentials = [ 'username' => config('anvil.anvil_username'), 'password' => config('anvil.anvil_password'), ];
We will also initialize our Guzzle client with the app's url.
$client = new Client(['base_uri' => config('anvil.anvil_endpoint')]);
Now that we have the basic requirements to connect to the API, let's give it a try.
The first step in the process is to obtain an access token.
try { $response = $client->post('services/oauth2/token', [ RequestOptions::FORM_PARAMS => [ 'grant_type' => 'password', 'client_id' => $apiCredentials['client_id'], 'client_secret' => $apiCredentials['client_secret'], 'username' => $userCredentials['username'], 'password' => $userCredentials['password'] . $apiCredentials['security_token'], ] ]);1$data = json_decode($response->getBody());} catch (\Exception $e) { throw new \Exception( sprintf('Could not connect to the Salesforce API: %s', $e->getMessage()) ); }
If all goes well, we will have a $data
object. We will be concerned with 4 properties:
$data->id
(used for hash comparison)$data→issued_at
(used for hash comparison)$data->signature
(used for hash comparison)$data->access_token
The next step is to validate that the access token returned is legitimate. We do this by comparing a generated hash to the signature
property that was returned in our $data
object.
$hash = hash_hmac( 'sha256', $data->id . $data->issued_at, $apiCredentials['client_secret'], true ); if (base64_encode($hash) !== $data->signature) { throw new \Exception('The Salesforce Access Token is invalid'); }
Finally we can make any API calls we need by passing the new token. In our case we have been mainly using the query endpoint with standard SOQL (Salesforce Object Query Language) queries as it is very similar to SQL.
You will notice the headers we are sending along with each request. The important one for this post is the Authorization
header. In this is where we pass the $data->access_token
as a Bearer token. We will talk about the other headers in a following post coming soon.
$query = "services/data/v50.0/query/?q=SELECT+YOUR+QUERY+HERE..."; $response = $client->get($query, [ RequestOptions::HEADERS => [ 'Authorization' => 'Bearer ' . $data->access_token, 'X-PrettyPrint' => 1, 'Sforce-Query-Options' => 'batchSize=2000', ], ]);
Hopefully this will help you get started with connecting to the Salesforce REST API with Laravel. 🍻