3

I am building a web application using Laravel that uses a Google Account as a sign-in method. I've downloaded the Google+ PHP API from Github and wrote a singleton class for accessing the Google+ service. A snippet of this class is shown below:

// Returns a client ready to receive an access token.
private static function getClient() {
  if (!self::$client) {
    self::$client = new Google_Client();
    self::$client->setApplicationName(self::$application_name);
    self::$client->setClientId(self::$client_id);
    self::$client->setClientSecret(self::$client_secret);
    self::$client->setAccessType('offline');
    // I'm only requesting the plus.login and userinfo.profile scopes.
    self::$client->setScopes(self::$scopes);
    // RedirectURI = 'postmessage'
    self::$client->setRedirectUri(self::$redirect_uri);
  }
  return self::$client;
}

// Returns a client ready to be used for API calls.
private static function getClient2() {
  $c = self::getClient();
  // getToken returns the token session variable. This is the full
  // JSON encoded token we got after authenticating the code.
  $token = self::getToken();
  $c->setAccessToken($token);
  if ($c->isAccessTokenExpired()) {
    // getRefreshToken returns the refresh_token session variable.
    // This is a JSON decoded string that only contains
    // the refresh_token value.
    $refreshToken = self::getRefreshToken();

    // This is the line that blows up.
    $c->refreshToken($refreshToken);

    // This code has never been reached :(
    $newToken = $c->getAccessToken();
    self::storeToken($newToken);
  }

  // If the access_token hasn't expired, we can merrily begin using
  // the client to construct a Google_Service_Plus object.
  return $c;
}

I am implementing the hybrid client/server flow. The first time a user signs on, a JavaScript callback is called which sends a code to be authenticated. The user is authenticated, the refresh_token is stored in a database and in the current session, and I can successfully make API calls for the life of the access_token.

After an hour, the access token expires. I test for this in getClient2() and attempt to refresh the access_token using the refresh_token retrieved from the session (I have printed the session variables and can confirm they exist and are json_decoded). I then get the beautifully descriptive error

Error refreshing the OAuth2 token, message: 'invalid_grant'

At this point all pages depending on Google+ show an error page. The site becomes unresponsive unless the user returns to the site home page where JavaScript begins the sign-in flow again, allowing the server to obtain a valid access_token for another hour.

I can post more of the singleton class if needed, but I think this is all that is relevant considering I am able to authenticate the user and make requests for the first hour.

Questions that are similar, but have not helped:

Community
  • 1
  • 1

1 Answers1

0

If you're looking to refresh your access token using a refresh token you can do

$client->refreshToken( $refresh_token );
$_SESSION['token'] = $client->getAccessToken();

You will get the invalid_grant returned if you are trying to refresh something other than your most recently granted refresh token.

Anders Marzi Tornblad
  • 17,122
  • 9
  • 50
  • 62