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 |
|
![]() 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 ); } } ?>
![]() 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?
![]() 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.
![]() 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!
![]() 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.
![]() 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.
![]() 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! |
info at phpclasses dot org
.