Authenticating with the Google Drive API using an indefinite refresh token

Wed, 23 January 2019

google-drive-access.php
//
// This redirect uri must be whitelisted and applied in the 'API' section of the Google Cloud Console.
// The full path to the resource is needed, not just the domain name.
//
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
$credentials = '{"web":{"client_id":"zjztQk4qG4PbdP7VUAtUCwaXRi8OFnj2-YOnRUZiORF17v2D4ZFOpkFfFxo0CKJ1d.apps.googleusercontent.com","project_id":"my-google-project-id","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"vhyWj4h7ZLyqRnAkFVcPwqKwhFPHyU1c"}}';
$oauth_credentials = json_decode($credentials, true);

if (!$oauth_credentials) {
    echo 'No oauth credentials';
    exit;
}

$client = new Google_Client();
$client->setAuthConfig($oauth_credentials);
$client->setRedirectUri($redirect_uri);
$client->setAccessType("offline");
$client->setApprovalPrompt("force");
$client->addScope("https://www.googleapis.com/auth/drive");
$service = new Google_Service_Drive($client);

//
// Step 1
//
// If no refresh token, redirect to the Google auth page.
//
//    1) Check the database for a refresh token for this user, if we have one, check it works.
//    2) If it doesn't work, redirect the user to the auth url.
//
if (!isset($_GET['code']) && empty($_SESSION['refresh_token'])) {
    $authUrl = $client->createAuthUrl();
    header('Location: ' . filter_var($authUrl, FILTER_SANITIZE_URL));
    exit;
}

//
// Step 2
//
// Retrieved initial code from Google to retrieve an access token. Access tokens only last 1 hour. Refresh tokens
// last indefinitely.
//
//    1) Get the access token.
//    2) Get the refresh token -> Store this in the database.
//
if (isset($_GET['code'])) {
    $token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
    $client->setAccessToken($token);
    $refreshToken = $client->getRefreshToken();
    $_SESSION['refresh_token'] = $refreshToken; // or from a db
    header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
    exit;
}

//
// Step 3
//
// We've got the refresh token, using that we can fetch an access token
// refresh tokens never expire - although they can be revoked by the user.
//
//    1) Fetch an access token using the refresh token (this access token changes every request then).
//    2) Using this new access token we have access to the Google Drive API
//    3) Create an example file.
//
if (!empty($_SESSION['refresh_token'])) {
    $randomFileName = 'test-file' . uniqid() . '.txt';
    $accessToken = $client->fetchAccessTokenWithRefreshToken($_SESSION['refresh_token']);

    $file = new Google_Service_Drive_DriveFile();
    $file->setName($randomFileName);
    $result = $service->files->create(
        $file,
        array(
            'data' => sprintf('This is a test file called %s', $randomFileName),
            'mimeType' => 'text/plain',
            'uploadType' => 'media'
        )
    );
    echo '<h1>Create file result:</h1>';
    echo sprintf(
        '<a href="https://drive.google.com/open?id=%s" target="_blank">%s (File ID: %s)</a>',
        $result->id,
        $result->name,
        $result->id
    );
    echo '<hr>';
    echo '<h1>Access Token Data:</h1>';
    var_dump($accessToken);
}