Unable to refresh OAuth2 token in PHP, invalid grant

15,301

Solution 1

This page https://developers.google.com/accounts/docs/OAuth2WebServer#offline explains how the refresh token works, and how to use it to get a fresh access token using raw http.

From this question How to refresh token with Google API client? here is the php equivalent

here is the snippet to set token, before that make sure the access type should be set to offline

if (isset($_GET['code'])) {
  $client->authenticate();
  $_SESSION['access_token'] = $client->getAccessToken();
}
To refresh token

$google_token= json_decode($_SESSION['access_token']);
$client->refreshToken($google_token->refresh_token);
this will refresh your token, you have to update it in session for that you can do

 $_SESSION['access_token']= $client->getAccessToken()

DEBUGGING Follow these three steps to debug any oauth application

  1. Make sure you have read https://developers.google.com/accounts/docs/OAuth2 and also the appropriate sub-page (webapp, javascript, etc) depending on which flavour of oauth you are using. You won't get very far debugging your app if you don't understand what it's doing.

  2. Use the Oauth Playground at https://developers.google.com/oauthplayground/ to walk through the Oauth steps and ultimately make a Google API call. This will confirm your understanding and show you what the http calls and responses look like

  3. Use tracing/logging/proxy etc to trace the actual http traffic from your app. Compare this with what you observed in step 2. This should show you where the problem lies.

Solution 2

I got this error before because I was trying to authenticate twice.

Since you have this line:

if (isset($_GET['code']))

It will try to authenticate when the code is in the query string regardless of whether you're already authenticated. Try checking whether the SESSION token is present before trying to (re)authenticate.

Share:
15,301

Related videos on Youtube

Roberto Milani
Author by

Roberto Milani

empty set

Updated on September 16, 2022

Comments

  • Roberto Milani
    Roberto Milani over 1 year

    I need to make a PHP script that creates a sigle event on Google Calendar. I had no problems setting up client id, client secret, dev key and creating a new event.

    My only problem is with OAuth2, in particular I need to make a permanent connection and I do not want to do the authentication everytime I run the script.

    Actually, with this script I'm able to get a token and a refresh token, but every hour my token expires and I don't know how to refresh it. How can I edit this code to do that? Can I save both the token and the refresh token somewhere and always use the same data?

    I obtain an uncaught exception 'Google_AuthException' with message 'Error refreshing the OAuth2 token, message: '{ "error" : "invalid_grant"

    I have already read some other posts about this topic here in stackoverflow but I still haven't found a solution... :\

    <?php
    
     require_once 'src/Google_Client.php';
     require_once 'src/contrib/Google_CalendarService.php';
     session_start();
    
     $client = new Google_Client();
     $client->setApplicationName("Calendar App");
     $client->setClientId('xxxx');
     $client->setClientSecret('yyy');
     $client->setRedirectUri('http://www.zzzzzz');  
     $client->setDeveloperKey('kkk');
     $client->setAccessType('offline');
     $cal = new Google_CalendarService($client);    
    
    if (isset($_GET['logout'])) {
      unset($_SESSION['token']);
    }
    
    if (isset($_GET['code'])) {
      $client->authenticate($_GET['code']);
      $_SESSION['token'] = $client->getAccessToken();
      header('Location: http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']); 
    }
    
    if (isset($_SESSION['token'])) {
        //echo $_SESSION['token'];
      //$client->setAccessToken($_SESSION['token']);
        $authObj = json_decode($_SESSION['token']);
        $accessToken = $authObj->access_token;
        $refreshToken = $authObj->refresh_token;
        $tokenType = $authObj->token_type;
        $expiresIn = $authObj->expires_in;
        echo 'access_token = ' . $accessToken;
        echo '<br />';
        echo 'refresh_token = ' . $refreshToken;
        echo '<br />';
        echo 'token_type = ' . $tokenType;
        echo '<br />';
        echo 'expires_in = ' . $expiresIn;
    }
    
    if(!empty($cookie)){
        $client->refreshToken($this->Cookie->read('token'));
    }
    
    if ($client->getAccessToken()) {
        $calList = $cal->calendarList->listCalendarList();
        $_SESSION['token'] = $client->getAccessToken();
    } else {
      $authUrl = $client->createAuthUrl();
      print "<a class='login' href='$authUrl'>Connect Me!</a>";
    }
    
    
    // Creation of a single event
    $event = new Google_Event();
    $event->setSummary($event_name);            
    $event->setLocation('');                    
    ....
    
    ?>
    

    Thanks a lot for your support!