Refresh tab causing invalid authorization code

This is my first post so I am sorry if the formatting is off. Basically I am trying to get acclimated with the api for infusionsoft so that I can build an application. Right now I’m just pulling some basic data from contacts but my code only works the first time I authorize. To be comprehensive, what is happening is I reach the website and it asks me to authorize. I click the link, sign in, and authorize the application with my account it then sends me back to index.php with the contact information I requested; so far so good. The problem occurs when I press refresh. I assume that it should just resend the contact information I originally requested but instead it gives me “400 bad request” error stating the authorization code is invalid. Any help would be greatly appreciated so that I can move forward. My entire code is given below. Thanks community.

<?php //if(empty(session_id())){} //session_start(); require_once 'vendor/autoload.php'; ?>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">

<!-- jQuery library -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<!-- Latest compiled JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <link href="https://fonts.googleapis.com/css?family=Merriweather|Oswald" rel="stylesheet">
<?php
  $infusionsoft = new \Infusionsoft\Infusionsoft(array(
  'clientId'     => 'xxxx',
  'clientSecret' => 'xxxx',
  'redirectUri'  => 'http://example.com',
  ));

  // 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()) {
  // Save the serialized token to the current session for subsequent requests
  $_SESSION['token'] = serialize($infusionsoft->getToken());

  $table = "Contact";
  $limit = 10;
  $page = 0;
  $queryData = array("Id" => "~>=~71251");
  $selectedFields = array("FirstName");
  $orderBy = "FirstName";
  $ascending = true;

  $infusionsoft->refreshAccessToken();
  $contact = $infusionsoft->data()->query($table, $limit, $page, $queryData, $selectedFields, $orderBy, $ascending);

  //This section loops through array assigns as (Like SQL) and goes through that array
  echo "<pre>";
  echo "First";
  foreach ( $contact as $var ) {
      echo "\n", $var['FirstName'], "\t";
  }

  // MAKE INFUSIONSOFT REQUEST
  } else {
  echo '<div class="centering"><a href="' . $infusionsoft->getAuthorizationUrl() . '" class="auth">Click here to authorize</a></div>';
}
?>

Also I did put my clientId and secret properly into the application as well as the redirect url I just put dummy information in for this post

If you’re clicking refresh then you’re trying to use the same authorization token to request an access token after it’s already been used and that means the authorization token has been invalidated and can no longer be used.

It sounds like you’re confusing the idea of an authorization toke with an access token. The example code would do this for you unseen so it may be unclear.

You use the auth token to request the right to get an access token (which is when the allow/deny screen comes into play). You are passed back an access token that allow you to make api calls to that connected app only. To make successive api calls you have to use the same access token but you do not want to re-request for an access token using the old auth token (which is what would be happening if you click refresh). Later, before the access token expires within 24 hours, you can use the refresh token that is passed at the same time the access token is, to get a completely new set of access/refresh tokens to continue using the connection without having to involve re-authorization again. These tokens are most commonly managed in a database in periodically checked to time to live and refresh before they expire.

Okay I didn’t realize that was happening. Well the refresh issue remains a problem because if one of our end users refreshes the browser and it sends them an error like that they aren’t going to know what to do. Is there any known workarounds for this issue or will I just have to write something in javascript that will require them to go back to the authorization page and reauthorize the app? Thanks for the help!

The known work around is to have the authorize process separate. It shouldn’t be part of the main process/product

Alright I moved the authorization to my index page and moved everything else to a home page but I am still having the refresh issue. I’m wondering if the session variable isn’t being set properly in my code since I keep getting the “Authorization code is invalid” error or possibly if I shouldn’t be recreating the infusionsoft variable in home.php. Again any help would be great, thanks

Here’s what everything looks like now

index.php

<?php if(empty(session_id())){} session_start(); require_once 'vendor/autoload.php'; ?>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">

<!-- jQuery library -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<!-- Latest compiled JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Merriweather|Oswald" rel="stylesheet">
<script src="script.js"></script>
<?php
  $infusionsoft = new \Infusionsoft\Infusionsoft(array(
  'clientId'     => 'x',
  'clientSecret' => 'x',
  'redirectUri'  => 'http://x/home.php',
  ));

	echo '<div class="centering"><a href="' . $infusionsoft->getAuthorizationUrl() . '" class="auth">Click here to authorize</a></div>';
?>

home.php

<?php require_once 'vendor/autoload.php'; ?>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">

<!-- jQuery library -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<!-- Latest compiled JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <link href="https://fonts.googleapis.com/css?family=Merriweather|Oswald" rel="stylesheet">
<?php
  $infusionsoft = new \Infusionsoft\Infusionsoft(array(
  'clientId'     => 'x',
  'clientSecret' => 'x',
  'redirectUri'  => 'http://x/home.php',
  ));

  // 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'])) {
    echo "<script>console.log('here1')</script>";
  	$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()) {
    echo "<script>console.log('here2')</script>";
  	$_SESSION['token'] = serialize($infusionsoft->requestAccessToken($_GET['code']));
  }

  if ($infusionsoft->getToken()) {
    echo "<script>console.log('here3')</script>";
    // Save the serialized token to the current session for subsequent requests
    $_SESSION['token'] = serialize($infusionsoft->getToken());

    // MAKE INFUSIONSOFT REQUEST

  $table = "Contact";
  $limit = 10;
  $page = 0;
  $queryData = array("Id" => "~>=~71251");
  $selectedFields = array("FirstName");
  $orderBy = "FirstName";
  $ascending = true;

  $infusionsoft->refreshAccessToken();
  $contact = $infusionsoft->data()->query($table, $limit, $page, $queryData, $selectedFields, $orderBy, $ascending);

  //This section loops through array assigns as (Like SQL) and goes through that array
  echo "<pre>";
  echo "First";
  foreach ( $contact as $var ) {
      echo "\n", $var['FirstName'], "\t";
    }
}
?>

If the focus is the refresh cycle then the session variable isn’t what will do it. That doesn’t account for all manner of reasons that it wouldn’t be available when needed. Most often, the access and refresh tokens, along with the expiration date of the access token, are stored in a database. Then, say every hour, run a script that reads this row and at the right time (say 20 hours in to be sure) run the refresh cycle and when successful, update the database row with the new set of access and refresh tokens and the new expiry.

@John_Borelli is correct storing this information to a database is best practice. The flow would be something like this:

  • Have user authorize access and obtain an access token, refresh token and expires in amount
  • Use the access token from the database whenever making an API call to Infusionsoft
  • Create a cron job that will run based off of the expires_in amount. This should run three hours before the access token expires and will obtain a new access token refresh token and expires_in amount. Save these values to the database.

Step 2 and 3 would continue to happen so the user doesn’t need to authorize access every time they want to use the applications.

1 Like

Is this still the flow for OAuth? I was planning to store the auth token, but it looks like it can not be reused. So i will store the access and refresh tokens. Is there any other way to not use a cron job to update the tokens? and also not have to re-prompt the user for permission?

No, you will need to refresh the tokens regularly to maintain authentication. This is an industry-standard method for mitigating compromised access.