Automatically refresh token using google drive api with php script

30,910

Solution 1

You don't have to periodically ask for an access token. If you have a refresh_token, PHP client will automatically acquire a new access token for you.

In order to retrieve an refresh_token, you need to set access_type to "offline" and ask for offline access permissions:

$drive->setAccessType('offline');

Once you get a code,

$_GET['code']= 'X/XXX';
$drive->authenticate();

// persist refresh token encrypted
$refreshToken = $drive->getAccessToken()["refreshToken"];

For future requests, make sure that refreshed token is always set:

$tokens = $drive->getAccessToken();
$tokens["refreshToken"] = $refreshToken;
$drive->setAccessToken(tokens);

If you want a force access token refresh, you can do it by calling refreshToken:

$drive->refreshToken($refreshToken);

Beware, refresh_token will be returned only on the first $drive->authenticate(), you need to permanently store it. In order to get a new refresh_token, you need to revoke your existing token and start auth process again.

Offline access is explained in detail on Google's OAuth 2.0 documentation.

Solution 2

After messing a lot I got this to work. I am using one file/script to get the offline token and then a class to do stuff with the api:

require_once 'src/Google/autoload.php'; // load library

session_start();

$client = new Google_Client();
// Get your credentials from the console
$client->setApplicationName("Get Token");
$client->setClientId('...');
$client->setClientSecret('...');
$client->setRedirectUri('...'); // self redirect
$client->setScopes(array('https://www.googleapis.com/auth/drive.file'));
$client->setAccessType("offline");
$client->setApprovalPrompt('force'); 



if (isset($_GET['code'])) {
    $client->authenticate($_GET['code']);
    $_SESSION['token'] = $client->getAccessToken();
    $client->getAccessToken(["refreshToken"]);
    $redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
    header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
    return;
}

if (isset($_SESSION['token'])) {
    $client->setAccessToken($_SESSION['token']);
}

if (isset($_REQUEST['logout'])) {
    unset($_SESSION['token']);
    $client->revokeToken();
}


?>
<!doctype html>
<html>
    <head><meta charset="utf-8"></head>
    <body>
        <header><h1>Get Token</h1></header>
        <?php
        if ($client->getAccessToken()) {
            $_SESSION['token'] = $client->getAccessToken();
            $token = json_decode($_SESSION['token']);
            echo "Access Token = " . $token->access_token . '<br/>';
            echo "Refresh Token = " . $token->refresh_token . '<br/>';
            echo "Token type = " . $token->token_type . '<br/>';
            echo "Expires in = " . $token->expires_in . '<br/>';
            echo "Created = " . $token->created . '<br/>';
            echo "<a class='logout' href='?logout'>Logout</a>";
            file_put_contents("token.txt",$token->refresh_token); // saving access token to file for future use
        } else {
            $authUrl = $client->createAuthUrl();
            print "<a class='login' href='$authUrl'>Connect Me!</a>";
        }
        ?>
    </body>
</html>

You can load refresh token from file and use it as necessary for offline access:

class gdrive{

function __construct(){
        require_once 'src/Google/autoload.php';
        $this->client = new Google_Client();
}

function initialize(){
        echo "initializing class\n";
        $client = $this->client;
        // credentials from google console
        $client->setClientId('...');
        $client->setClientSecret('...');
        $client->setRedirectUri('...');

        $refreshToken = file_get_contents(__DIR__ . "/token.txt"); // load previously saved token
        $client->refreshToken($refreshToken);
        $tokens = $client->getAccessToken();
        $client->setAccessToken($tokens);

        $this->doSomething(); // go do something with the api       
    }
}

More here: https://github.com/yannisg/Google-Drive-Uploader-PHP

Share:
30,910
Huxley
Author by

Huxley

Updated on July 15, 2022

Comments

  • Huxley
    Huxley almost 2 years

    I followed again THIS TUTORIAL to upload a file on Google Drive with php, directly from my REMOTE SERVER: so I have created new API Project from Google API Console, enabled Drive API service, requested OAuth Client ID and Client Secret, wrote them in a script, then upload it together with Google APIs Client Library for PHP folder to this http://www.MYSERVER.com/script1.php, to retrieve Auth code:

    <?php
    
    require_once 'google-api-php-client/src/Google_Client.php';
    require_once 'google-api-php-client/src/contrib/Google_DriveService.php';
    
    $drive = new Google_Client();
    
    $drive->setClientId('XXX'); // HERE I WRITE MY Client ID
    
    $drive->setClientSecret('XXX'); // HERE I WRITE MY Client Secret
    
    $drive->setRedirectUri('urn:ietf:wg:oauth:2.0:oob');
    
    $drive->setScopes(array('https://www.googleapis.com/auth/drive'));
    
    $gdrive = new Google_DriveService($drive);
    
    $url = $drive->createAuthUrl();
    $authorizationCode = trim(fgets(STDIN));
    
    $token = $drive->authenticate($authorizationCode);
    
    ?>
    

    When I visit http://www.MYSERVER.com/script1.php I allow authorization and get the Auth code that I can write in a second script. Then I upload it to http://www.MYSERVER.com/script2.php, who looks like:

    <?php
    
    require_once 'google-api-php-client/src/Google_Client.php';
    require_once 'google-api-php-client/src/contrib/Google_DriveService.php';
    
    $drive = new Google_Client();
    
    $drive->setClientId('X');  // HERE I WRITE MY Client ID
    $drive->setClientSecret('X');  // HERE I WRITE MY Client Secret
    $drive->setRedirectUri('urn:ietf:wg:oauth:2.0:oob');
    $drive->setScopes(array('https://www.googleapis.com/auth/drive'));
    
    $gdrive = new Google_DriveService($drive);
    
    $_GET['code']= 'X/XXX'; // HERE I WRITE AUTH CODE RETRIEVED AFTER RUNNING REMOTE script.php
    
    file_put_contents('token.json', $drive->authenticate());
    
    $drive->setAccessToken(file_get_contents('token.json'));
    
    $doc = new Google_DriveFile();
    
    $doc->setTitle('Test Drive');
    $doc->setDescription('Document');
    $doc->setMimeType('text/plain');
    
    $content = file_get_contents('drive.txt');
    
    $output = $gdrive->files->insert($doc, array(
          'data' => $content,
          'mimeType' => 'text/plain',
        ));
    
    print_r($output);
    
    ?>
    

    Well, now the file drive.txt is uploaded on my Google Drive and structure of token.json file is a sort of:

    {"access_token":"XXX","token_type":"Bearer","expires_in":3600,"refresh_token":"YYY","created":1365505148}
    

    Now, as you can imagine I can call script2.php and upload file until a certain time. Finally, the point is: I don't want the token to expire, I don't want to allow authorization each time it expire (recalling script1.php): I need to call the script2.php periodically during the day, to upload my file automatically, without user interaction. So, what's the best way to automatically refresh the token forever in this context? Do I need another script? Can I add some code to script2.php? or modify the token.json file? And where can I read the time remaining before the token expire? Thanks!

  • Huxley
    Huxley about 11 years
    Thank you @Burcu, the point is in your words "If your access token is expired": WHEN I CAN VIEW that my access token is expired? is it permanent or not?
  • Burcu Dogan
    Burcu Dogan about 11 years
    @Huxley, it will throw an Google_AuthException. On the other hand, this client library automatically refresh access token if the current one is about to expire. So, normally you should never see an auth error. I'm editing my answer above.
  • Huxley
    Huxley about 11 years
    I have retrieved refresh_token and access_token from OAuth 2.0 Playground console and stored it in my token.json file: it's the same thing? are they permanent?
  • Burcu Dogan
    Burcu Dogan about 11 years
    @Huxley, you can't use a refresh_token retrieved by OAuth 2.0 Playground, you need to retrieve tokens with your own client id and client secret. Otherwise, PHP lib will not be able to refresh the access token. /* Offline access permission is given to OAuth 2.0 Playground, not your app. */
  • Huxley
    Huxley about 11 years
    Well, @Burcu, but if you see my question in the token.json file I have ALREADY refresh and access token retrieved after the first authentication and the first call of script2.php, in fact I can upload perfectly the files: Do I still need to retrieve other tokens? thanks for your patience :)
  • Burcu Dogan
    Burcu Dogan about 11 years
    @Huxley, once you retrieve them the way you do in your example, you can store them and use on anywhere you like, you dont need to get into any other auth flow anymore. Refresh tokens never expire, FYI.
  • Huxley
    Huxley about 11 years
    Perfect, @Burcu, I was a little confused because after my example (script2.php) you answered with ANOTHER way to retrieve refresh token, so I thought mine was wrong and your was the ONLY way! After the first authentication I have stored tokens so now I'm using a little variation of the script2.php and, as u wrote, "PHP client will automatically acquire a new access token". Thank you again!
  • Eswar Rajesh Pinapala
    Eswar Rajesh Pinapala about 10 years
    Please change $drive->setAccessToken(tokens); to $drive->setAccessToken($tokens); I guess its a typo(Hoping between Java & PHP worlds huh? ;) )!
  • Stormsson
    Stormsson over 9 years
    Dude ,thank you, the line that helped me was the information about the fact that the refresh token was returned only the FIRST time of the auth.