PHP Classes

Refresh token (for Exact Online)

Recommend this page to a friend!

      PHP OAuth Library  >  PHP OAuth Library package blog  >  How to Implement a PH...  >  All threads  >  Refresh token (for Exact Online)  >  (Un) Subscribe thread alerts  
Subject:Refresh token (for Exact Online)
Summary:Refresh token needs other URL
Messages:7
Author:Lars van Bommel
Date:2015-08-14 17:24:42
 

  1. Refresh token (for Exact Online)   Reply   Report abuse  
Picture of Lars van Bommel Lars van Bommel - 2015-08-14 17:24:42
Dear reader,

I have a working connection with Exact, but I can't get the refresh token to work.
I searched for examples in your download and this forum, but can't seem to get it to work.

We use the oAuth library to connect with Exact, which is an accounting company which we use in our custom CMS built on CakePHP for retrieving items for the webshop in this example.
The version I am using is: v 1.139 2015/07/23 20:41:37 mlemos

The only way to refresh the token is as described below, but the page has to be reloaded and all entered data is gone.
Since it is a CMS, this is a big problem.
Watching your examples, the redirect shouldn't be necessary, but if I remove it, the refresh token is not used at all.


In the oauth_client.php I added the following in Function Initialize():
case 'Exact':
$this->oauth_version = '2.0';
$this->dialog_url = 'https://start.exactonline.nl/api/oauth2/auth?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&response_type=code&state={STATE}';

if( isset($_GET['code']) )
$this->access_token_url = 'https://start.exactonline.nl/api/oauth2/token?client_id={CLIENT_ID}&client_secret={$this->client_secret}&code=' . $_GET['code'];
elseif(isset($this->refresh_token))
$this->access_token_url = 'https://start.exactonline.nl/api/oauth2/token?refresh_token=' . $this->refresh_token;
break;



The code currenlty used on the page I'm loading is basic:

$ExactOnline = App::invoke('component', 'ExactOnline');
$itemgroupsExact = $ExactOnline->get('/v1/42312/Logistics/ItemGroups');


This calls exactcomponent and enters the URL parameters for the CallAPI.

The code in the ExactOnline Component is derived from your login_with_google.php:


<?php

require_once(APP . DS . 'vendors' . DS . 'http.php');
require_once(APP . DS . 'vendors' . DS . 'oauth_client.php');
require_once(APP . DS . 'vendors' . DS . 'database_oauth_client.php');
require_once(APP . DS . 'vendors' . DS . 'mysqli_oauth_client.php');


class ExactOnlineComponent
{
private $apiKey;
private $client_id;
private $client_secret;
private $client = null;
private $division = null;
private $baseUrl = 'https://start.exactonline.nl/api';
private $OauthSessionModel = null;
private $oauthSession = null;

public function __construct()
{
$webshopSetting = App::invoke('model', 'WebshopSetting')->getList('value');
$this->division = $webshopSetting['exact_division'];


if(is_null($this->OauthSessionModel))
$this->OauthSessionModel = App::invoke('model', 'OauthSession');


//Set redirect url
if( !isset($_GET['code']) && isset($_SERVER['HTTP_REFERER']) )
$_SESSION['redirectUrl'] = $_SERVER['HTTP_REFERER'];
else
$_SESSION['redirectUrl'] = 'http://' . $_SERVER['HTTP_HOST'] . '/cms/webshop/products_products';

if(is_null($this->client))
{
$this->client = new mysqli_oauth_client_class;

$this->client->database = array(
'host' => Config::$database['server'],
'user' => Config::$database['user'],
'password' => Config::$database['password'],
'port' => 3306,
'name' => Config::$database['database'],
'socket' => ''
);


$this->client->client_id = $webshopSetting['exact_client_id'];
$this->client->client_secret = $webshopSetting['exact_client_secret'];
$this->client->server = 'Exact';
//redirect to function in MVC framework which essentially calls $this->auth();
$this->client->redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/webshop/auth';
$this->client->offline = true;

if(strlen($this->client->client_id) == 0
|| strlen($this->client->client_secret) == 0)
die('Please set client id/secret');
}

$this->client->debug = false;
// Check for active cookie
if( isset($_COOKIE['oauth_session'] ) && strlen($_COOKIE['oauth_session']) > 0 )
{
$this->oauthSession = $this->OauthSessionModel->find(array('session' => $_COOKIE['oauth_session']));

// Check if session still active and correct for time difference of 2 hours between servers
if( !is_null($this->oauthSession) && strlen($this->oauthSession['OauthSession']['expiry']) > 0 && strtotime($this->oauthSession['OauthSession']['expiry']) < strtotime("-2 hours", time()) )
{
$this->client->ResetAccessToken();
$this->auth();
}
$this->client->Initialize();
}
else
$this->auth();

// Check if session still active and correct for time difference of 2 hours between servers
if( !is_null($this->oauthSession) && strtotime($this->oauthSession['OauthSession']['expiry']) < strtotime("-2 hours", time()) )
$this->client->Process();
}

public function auth()
{
if(($success = $this->client->Initialize()))
{
if(($success = $this->client->Process()))
{
if(strlen($this->client->authorization_error))
{
$this->client->error = $this->client->authorization_error;
$success = false;
}
else if(strlen($this->client->access_token))
{
//vorige url uit session halen en redirect?
$this->client->SetUser(1);
$this->client->Finalize($success);
header('Location: ' . $_SESSION['redirectUrl']);
exit;
}
}
}
}

public function get($url = null, $guid = null)
{
if(is_null($url))
die('Set an url ');

$webshopSetting = App::invoke('model', 'WebshopSetting')->getList('value');
$this->division = $webshopSetting['exact_division'];
$response = $this->client->CallAPI
(
$this->baseUrl. $url . (is_null($guid) ? '' : '(guid\''. $guid .'\')') ,
'GET',
array(),
array('FailOnAccessError' => true, 'Accept' => 'application/json'),
$resource
);

if( $this->client->Finalize($response) )
{
if(strlen($resource->d->__next))
{
//refactor naar recursive
$nextUrl = str_replace($this->baseUrl, '', $resource->d->__next);
$nextResource = $this->get($nextUrl);
return array_merge($resource->d->results, $nextResource);
}

return is_null($guid)? $resource->d->results : $resource->d;
}
else
die($this->client->error);
}

public function post($url = null, $data = null)
{
if( is_null($url) )
die('Set an url');

if( is_null($data) )
die('Set the data');

$response = $this->client->CallAPI
(
$this->baseUrl . $url,
'POST',
array(),
array('FailOnAccessError' => true, 'Accept' => 'application/json', 'RequestBody' => json_encode($data), 'RequestContentType' => 'application/json'),
$resource
);

if( $this->client->Finalize($response) )
return $resource->d->results;
else
die($this->client->error);
}

public function put($url = null, $guid = null, $data = null)
{
if( is_null($url) )
die('Set an url too post to');

if( is_null($data) )
die('Set the data too post');

if( is_null($guid) )
die('Set the item guid');

$this->client->CallAPI
(
$this->baseUrl . $url . '(guid\''. $guid .'\')',
'PUT',
array(),
array('FailOnAccessError' => true, 'Accept' => 'application/json', 'RequestBody' => json_encode($data), 'RequestContentType' => 'application/json'),
$resource
);
}

public function delete($url = null, $guid = null)
{
if( is_null($url) )
die('Set an url too post to');

if( is_null($guid) )
die('Set the item guid too delete');

$this->client->CallAPI
(
$this->baseUrl . $url . '(guid\''. $guid .'\')',
'DELETE',
array(),
array('FailOnAccessError' => true, 'Accept' => 'application/json', 'RequestContentType' => 'application/json'),
$resource
);
}
}

?>


  2. Re: Refresh token (for Exact Online)   Reply   Report abuse  
Picture of Manuel Lemos Manuel Lemos - 2015-08-14 19:02:44 - In reply to message 1 from Lars van Bommel
When a token is refreshed, the refresh token is sent as a parameter of a POST request, not as a URL parameter as you may read in the documentation of OAuth 2.0:

tools.ietf.org/html/rfc6749#section ...

Are you sure that API requires that it goes in URL?

Is there any documentation of that API we can look?


  3. Re: Refresh token (for Exact Online)   Reply   Report abuse  
Picture of Lars van Bommel Lars van Bommel - 2015-08-19 06:17:33 - In reply to message 2 from Manuel Lemos
Dear Manuel,

Thank you for your fast response, and my apologies for the delay.
The documentation can be found here:
developers.exactonline.com/#OAuth_T ...
It seems it should go as a post param, however I am not sure how to implement it then.

  4. Re: Refresh token (for Exact Online)   Reply   Report abuse  
Picture of Lars van Bommel Lars van Bommel - 2015-08-19 11:29:10 - In reply to message 3 from Lars van Bommel
It seems that I have it working now. After fixing the refresh_token to be sent via POST, there was 1 more problem.

I had to add the following in the function SendAPIRequest right before $http->SendRequest($arguments);

if(IsSet($arguments['PostValues']) && IsSet($arguments['PostValues']['refresh_token']))
unset($arguments['Headers']['Authorization']);

The Bearer in the authorization header had to be removed in order to retrieve a new refresh token.

Thanks for you help!

  5. Re: Refresh token (for Exact Online)   Reply   Report abuse  
Picture of Manuel Lemos Manuel Lemos - 2015-08-20 21:25:04 - In reply to message 4 from Lars van Bommel
I cannot omit the Authorization header for all OAuth 2 API because they need it to identify the application.

Are you sure that API cannot refresh tokens when the Authorization header is present?

What I can do is to add an option to the class to omit the Authorization header when refreshing tokens specifically for that API.

  6. Re: Refresh token (for Exact Online)   Reply   Report abuse  
Picture of Manuel Lemos Manuel Lemos - 2015-08-22 21:18:30 - In reply to message 4 from Lars van Bommel
Well, I have just updated the class to make it possible not send authorization headers for some API like the one you are using.

Just set the variable refresh_token_authorization to "none" or in the oauth_configuration.json file.

  7. Re: Refresh token (for Exact Online)   Reply   Report abuse  
Picture of Lars van Bommel Lars van Bommel - 2015-08-24 06:44:23 - In reply to message 6 from Manuel Lemos
Great!
In that case I will download the newest version and update it so that my own code is gone and I can just use your updates for the future.

Thank you very much for your fast and good help!