Freshbooks is an online invoicing an accounting app used as an alternative to Quickbooks. With a simple UI and an easy to use API for accessing invoices and processing payments it's a commonly selected tool for small to mid-size businesses and it's not uncommon to get requests to integrate their data into custom portals. Everything you need to know in order to get started including a few examples can be found in the FreshBooks API Documentation, but the first challenge is to get past the OAuth2 requirements.
First thing first, are we using a library to connect or are we just going to code our own? For this solution, we will show how to extend the oauth2-client package from The League of Extraordinary Packages.
Once you've installed the library, you'll need to extend the AbstractProvider, and of course provide it with credentials you will get after creating your application in Freshbooks. in order for everything to work. The skeleton is provided below and will get any project started, but more effort needs to be put in for any production ready deployment.
use League\OAuth2\Client\Provider\AbstractProvider; use League\OAuth2\Client\Token\AccessToken; use Psr\Http\Message\ResponseInterface; class FreshBooks extends AbstractProvider { public function getBaseAuthorizationUrl() { return 'https://auth.freshbooks.com/service/auth/oauth/authorize'; } public function getBaseAccessTokenUrl(array $params) { return 'https://api.freshbooks.com/auth/oauth/token'; } protected function getAuthorizationHeaders($token = null) { return ['Authorization' => 'Bearer ' . $token]; } public function getResourceOwnerDetailsUrl(AccessToken $token) {} protected function getDefaultScopes() {} protected function checkResponse(ResponseInterface $response, $data) {} protected function createResourceOwner(array $response, AccessToken $token) {} }
Then instantiate a Freshbooks object with your credentials.
$provider = new FreshBooks ([ 'clientId' => 'bunch-of-letters-and-numbers', 'clientSecret' => 'bunch-of-letters-and-numbers', 'redirectUri' => 'https://some.secure.url.where.script.is.hosted' ]);
Finally, copy the code from The League and test your results.
if (!isset($_GET['code'])) { // If we don't have an authorization code then get one. // This call also generates state so don't get clever with it. $authUrl = $provider->getAuthorizationUrl(); $_SESSION['oauth2state'] = $provider->getState(); header('Location: '.$authUrl); exit; // Check given state against previously stored one to mitigate CSRF attack } elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) { unset($_SESSION['oauth2state']); exit('Invalid state'); } else { // Try to get an access token (using the authorization code grant) $token = $provider->getAccessToken('authorization_code', [ 'code' => $_GET['code'] ]); // Use this to interact with an API on the users behalf echo '<p>Token: ' . $token->getToken() . '</p>'; // Build a request to get the account owner from Freshbooks. $request = $provider->getAuthenticatedRequest( 'GET', 'https://api.freshbooks.com/auth/api/v1/users/me', $token ); // Send the request $response = $provider->getResponse($request); // Just dump the results. echo "<hr>Body:<hr><pre>"; var_dump(strval( $response->getBody() )); echo "</pre>"; }