Refresh access token

HI,
I’ve been trying to (refresh access token) using newest PHP SDK version existing on github. I couldn’t find any details on the subject in the documentation.
i’m trying to write this code :

<?php
require_once 'vendor/autoload.php';
require_once 'File.php';
require_once 'Config.php';

$infusionsoft = new \Infusionsoft\Infusionsoft(array(
	'clientId'     => CLIENT_ID,
	'clientSecret' => CLIENT_SECRET,
	'redirectUri'  => URL,
));

// If the serialized token is available in the session storage, we tell the SDK
// to use that token for subsequent requests.
$SavedToken = json_decode(File::GetFileContent('token'));
if (!empty($SavedToken->Value) && (strtotime("now") - strtotime($SavedToken->At)) < 86400 )  {
	$infusionsoft->setToken(unserialize($SavedToken->Value));
}

// If we are returning from Infusionsoft we need to exchange the code for an
// access token.
if (isset($_GET['code']) && !$infusionsoft->getToken()) {
    File::Truncate('token', json_encode(
        array(
            "At"=> date('Y-m-d H:i:s'),
            "Value" => serialize($infusionsoft->requestAccessToken($_GET['code']))
        )
    ));
    $infusionsoft->refreshAccessToken();
    echo ('New Access Token Saved');
    exit();
}

if ($infusionsoft->getToken()) {
    $saved_token = unserialize($SavedToken->Value);
    $token = new \Infusionsoft\Token([
        'access_token' => $saved_token->accessToken,
        'refresh_token' => $saved_token->refreshToken,
        'expires_in' => $saved_token->endOfLife,
    ]);

    $infusionsoft->setToken($token);
    $infusionsoft->refreshAccessToken();
    $token = $infusionsoft->getToken();


    echo ('Token Time not finished yet');
    exit();
} else {
    echo '<a href="' . $infusionsoft->getAuthorizationUrl() . '">Click here to authorize</a>';
    exit();    
}

but i faced the problem :

PHP Fatal error:  Uncaught GuzzleHttp\Exception\ClientException: Client error: `POST https://api.infusionsoft.com/token` resulted in a `400 Bad Request` response:
{"error":"invalid_grant","error_description":"Invalid refresh token"}
 in /home1/autotech/public_html/infusion/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php:113
Stack trace:
#0 /home1/autotech/public_html/infusion/vendor/guzzlehttp/guzzle/src/Middleware.php(66): GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Psr7\Request), Object(GuzzleHttp\Psr7\Response))
#1 /home1/autotech/public_html/infusion/vendor/guzzlehttp/promises/src/Promise.php(203): GuzzleHttp\Middleware::GuzzleHttp\{closure}(Object(GuzzleHttp\Psr7\Response))
#2 /home1/autotech/public_html/infusion/vendor/guzzlehttp/promises/src/Promise.php(156): GuzzleHttp\Promise\Promise::callHandler(1, Object(GuzzleHttp\Psr7\Response), Array)
#3 /home1/autotech/public_html/infusion/vendor/guzzlehttp/promises/src/TaskQueue.php(47): GuzzleHttp\Promise\Promise::GuzzleHttp\Promise\{closure}()
 in /home1/autotech/public_html/infusion/vendor/infusionsoft/php-sdk/src/Infusionsoft/Http/GuzzleHttpClient.php on line 74

Would you guys guide me in the right direction with a tested code!
Thank you

Hi @nasser_halabi, depending on which url you are using, the payload will look different.

There are 2 different urls
https://signin.infusionsoft.com/app/oauth/authorize
https://api.infusionsoft.com/token

to view their respective payloads, check out our getting started page here

This error looks like either the incorrect payload was sent, or the wrong url was used. For simple testing, I just store the token in the SESSION similar to the following:

<?php

session_start();

require_once '../vendor/autoload.php';

$infusionsoft = new \Infusionsoft\Infusionsoft(array(
    'clientId' => '',
    'clientSecret' => '',
    'redirectUri' => '',
));

// If the serialized token is available in the session storage, we tell the SDK
// to use that token for subsequent requests.
if (isset($_SESSION['token'])) {
    $infusionsoft->setToken(unserialize($_SESSION['token']));
}

// If we are returning from Infusionsoft we need to exchange the code for an
// access token.
if (isset($_GET['code']) and !$infusionsoft->getToken()) {
    $infusionsoft->requestAccessToken($_GET['code']);
}

if ($infusionsoft->getToken()) {
    try {
        //make a call to the Infusionsoft API
    } catch (\Infusionsoft\TokenExpiredException $e) {
        // If the request fails due to an expired access token, we can refresh
        // the token and then do the request again.
        $infusionsoft->refreshAccessToken();
    }
    
    // Save the serialized token to the current session for subsequent requests
    $_SESSION['token'] = serialize($infusionsoft->getToken());
} else {
    echo '<a href="' . $infusionsoft->getAuthorizationUrl() . '">Click here to authorize</a>';
}

Since you are writing this to a file, you will just want to ensure that the correct data is getting saved and that the url you are using is correct.

Using the above example, are you able to store an access token and use it in a request successfully? If so, I would just ensure that you are writing the correct values to your file.

Thank you @Carlos_Ochoa i’m trying your code by i still have to refresh my token each 24 hour ,
i need another help please…

I save access token in Database in first connection,
then i get last filed saved in database and call

if (isset($token) && !empty($token) ) {
    $infusionsoft->setToken(unserialize("MY_DB_QUERY_RESULT"));
}

But nothing happens, Then if 24 hour passed you must to update you token :frowning:

here is my code:

<?php
require_once 'vendor/autoload.php';
require_once 'Config.php';

$infusionsoft = new \Infusionsoft\Infusionsoft(array(
	'clientId'     => CLIENT_ID,
	'clientSecret' => CLIENT_SECRET,
	'redirectUri'  => 'MY_URL',
));

// If the serialized token is available in the session storage, we tell the SDK
// to use that token for subsequent requests.
$token = DB::queryFirstRow(
                'SELECT *
                FROM token
                ORDER BY ID DESC
                LIMIT 1');

if (isset($token) && !empty($token) ) {
    $infusionsoft->setToken(unserialize($token['Value']));
}

// If we are returning from Infusionsoft we need to exchange the code for an
// access token.
if (isset($_GET['code']) and !$infusionsoft->getToken()) {
    $infusionsoft->requestAccessToken($_GET['code']);
}

if ($infusionsoft->getToken()) {
    // Save the serialized token to the current session for subsequent requests
    $token = serialize($infusionsoft->getToken());
    DB::insert('token', array(
        'Value' => $token,
      ));
}
else
{
    echo '<a href="' . $infusionsoft->getAuthorizationUrl() . '">Click here to authorize</a>';
}

Thank you :slight_smile:

Hi @nasser_halabi, an access token will expire in 24 hours. You then need to make a call to refresh the token to get a new access token. As far as the code itself goes, I don’t see anything that stands out… I assume you are using something like MeekroDB? I am not too familiar with that myself, but as long as you are storing the valid access token and refreshing the expired token to get a new valid access token, this should work.

If your environment supports it, I recommend running a cron job to refresh the token before it expires.

Do you see this same issue with the code I supplied above?

1 Like

Thanks for your reply again :sunglasses:
I’m trying to build my own API to link between mobile apps and infusionsoft so Session solution is not work,
I need Database solution. Could you please help my .

@Carlos_Ochoa , @John_Borelli
Take a look guys , i’m in hurry :smile:

@nasser_halabi I am not sure that I could recommend something that would work for this. The code you supplied looks like it should work to me. Maybe @John_Borelli has a suggestion??

1 Like

Hi, @nasser_halabi,

So as you’ve indicated, you’re getting it to work. Your challenge is what happens after the expiration of the access token. So going by this symptom, what you are likely not doing is refreshing the token and THEN UPDATING THE DATABASE ROW with the NEW token information. Once you refresh your tokens, the existing one’s become invalid immediately and the new ones are your active ones so they must be used to update the database row. The best way to manage this seemlessly, and what I usually do, is to run an hourly service using CRON that checks to see if the tokens are close to expiring. I usually use the 4 hours or less timing as a time to start attempting refresh. If you get a good refresh, which you most often should, then update the DB row with the new information and date/time they were authorized. If for any reason, the refresh fails, then you have 2-3 more tries before the access token would expire naturally. This ensures a near 0% failure rate as you give it enough tries to almost certainly refresh correctly. The key is to set the date/time when a new set is aquired so that you can use that and the current date/time to determine how much time is left and then refresh early enough to give yourself a few attempts should it be required.

1 Like

Thank you @John_Borelli & @Carlos_Ochoa for your nice help, i’ll try this solution :slight_smile: