Skip to content
Advertisement

How to use Google Drive PHP Api with service account

I’ve written a series of functions to do things in Google Drive like copy folders, copy documents, get document content, etc. All of them work when I am authenticating as a particular user using OAuth. Now I have switched over to a service account to authenticate as my app, and the functions are no longer working. For intsance when I try to copy a doc, I get “File not found error” referring to the origin doc I want to copy. Again, works fine if I use OAuth. I have followed the google examples for authenticating as a service account but its not seeming to work.

Here is my code to getClient using service account:

{

    putenv("GOOGLE_APPLICATION_CREDENTIALS=credentials.json");
    $client = new Google_Client();
    $client->useApplicationDefaultCredentials();
    $client->setApplicationName('Application Name');
    $client->setScopes($scopes);

    return $client;

}

And here is my copy document function

function copyDocument($originId, $name, $parents)

{
    $client = getClient(Google_Service_Drive::DRIVE);
    $service = new Google_Service_Drive($client);
    $origin = $originId;
    $document = new Google_Service_Drive_DriveFile();
    $document->setParents(array($parents));
    $document->setName($name);
    $response = $service->files->copy($origin, $document);
    return $response;
}

This returns error:

Fatal error: Uncaught GoogleServiceException: {
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "notFound",
    "message": "File not found: 1TRRohZ1Ok4McyVFJ6OrySG2E4Q32nggakS27hU8QGAs.",
    "locationType": "parameter",
    "location": "fileId"
   }
  ],
  "code": 404,
  "message": "File not found: 1TRRohZ1Ok4McyVFJ6OrySG2E4Q32nggakS27hU8QGAs."
 }
}

Again, if I use the below as my getClient function, then copy folder works just fine.

function getClient($scopes)
{

    $client = new Google_Client();
    $client->setApplicationName('Application Name');
    $client->setScopes($scopes);
    $client->setAuthConfig(__DIR__ . '/credentials.json');
    $client->setAccessType('offline');
    $client->setPrompt('select_account consent');

    // Load previously authorized token from a file, if it exists.
    // The file token.json stores the user's access and refresh tokens, and is
    // created automatically when the authorization flow completes for the first
    // time.
    $tokenPath = 'token.json';
    if (file_exists($tokenPath)) {
        $accessToken = json_decode(file_get_contents($tokenPath), true);
        $client->setAccessToken($accessToken);
    }

    // If there is no previous token or it's expired.
    if ($client->isAccessTokenExpired()) {
        // Refresh the token if possible, else fetch a new one.
        if ($client->getRefreshToken()) {
            $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
        } else {
            // Request authorization from the user.
            $authUrl = $client->createAuthUrl();
            printf("Open the following link in your browser:n%sn", $authUrl);
            print 'Enter verification code: ';
            $authCode = trim(fgets(STDIN));

            // Exchange authorization code for an access token.
            $accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
            $client->setAccessToken($accessToken);

            // Check to see if there was an error.
            if (array_key_exists('error', $accessToken)) {
                throw new Exception(join(', ', $accessToken));
            }
        }
        // Save the token to a file.
        if (!file_exists(dirname($tokenPath))) {
            mkdir(dirname($tokenPath), 0700, true);
        }
        file_put_contents($tokenPath, json_encode($client->getAccessToken()));
    }
    
    return $client;

}

What is the proper way to auth as a service account???

Advertisement

Answer

From your question, I could understand that your script works. About your issue, I thought that in your situation, the following point might be the reason of your current issue.

  • The file of $origin = $originId; might be put in Google Drive of your email account.
  • And you might be trying to copy the file using the service account.

In this case, the service account cannot directly see the file on your Google Drive. Because the Drive of the service account is different from your Drive. When you want to copy the file on your Drive using the service account, for example, please share the file with the email of the service account. By this, the service account can see it and copy the file. If you can share a folder with the service account, the files in the folder can be also seen by the service account.

As the additional information, if your will use the service account to impersonate their regular account, please check domain-wide delegation as mentioned by Iamblichus’s comment.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement