Salesforce REST API, OAuth, and Laravel

April 9, 2021

Written By: Jerred Hurst

Salesforce REST API, OAuth, and Laravel

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. 🍻