Search code examples
google-apigoogle-drive-apigoogle-oauthgoogle-api-php-client

Creating a file with Google Drive API using a Service Account doesn't render file on authorized user account's GD


I'm currently trying to create a file and have it uploaded on a Google Drive account using the Service Account auth method provided by Google (since it'll all be server-side on the final product, I don't want users to have to authorize access, so no OAuth per-say).

I'm currently able to connect with the Service Account and upload the file, but the file doesn't show when I'm navigating my Google Drive.

(I was able to have it work (both upload & render) using the OAuth method; where I would manually authorize the application prior to the upload, so I'm pretty sure the code is working)

Also, another way that I know it's working is, once the upload has been done, I'm returned a file ID. If I were to go to "https://drive.google.com/file/d/FILE_ID/view?usp=sharing", I'm met with "Authorization is required".

Is there anything I should be doing when creating the Service Account so that my Gmail account can have access to the files?


For informations, here's the way I'm connecting to the API (Server-side):

<?php
$client = new Google_Client();

if ($this->oauth_credentials = $this->getServiceAccountCredentialsFile()) :
    $client->setAuthConfig($this->oauth_credentials);
endif;

if ($this->warning != null) :
    echo $this->warning;
    return;
endif;

$client->setApplicationName("Test Google Drive Service Account");
$client->setScopes(['https://www.googleapis.com/auth/drive']);
$service = new Google_Service_Drive($client);

define("TESTFILE", ABSPATH.'testfile-small.txt');
if (!file_exists(TESTFILE)) {
    $fh = fopen(TESTFILE, 'w');
    fseek($fh, 1024 * 1024);
    fwrite($fh, "!", 1);
    fclose($fh);
}

$file = new Google_Service_Drive_DriveFile();
$result = $service->files->create(
    $file,
    array(
        'data' => file_get_contents(TESTFILE),
        'mimeType' => 'application/octet-stream',
        'uploadType' => 'media'
    )
);
echo '<pre>'; var_dump($result->id); echo '</pre>';

Solution

  • You have four options...

    1. Don't use a Service Account. Just store a Refresh Token for the User Account. See How do I authorise an app (web or installed) without user intervention? . It's a myth that Service Accounts are the only option for Server access.
    2. Use a Service Account to write to a folder which has been shared by your User Account to the Service Account
    3. Use a Service Account to write to a folder which is shared by your Service Account to your User Account
    4. Use a Service Account within a G-Suite domain to impersonate the User Account

    Option 1. is the easiest, 2 and 3 only differ in terms of who owns the files and therefore against whose quota they are counted. 4 is only relevant for G-Suite