1
votes

PHP Fatal error: Uncaught Google\Service\Exception: { "error": "unauthorized_client", "error_description": "Client is unauthorized to retrieve access tokens using t his method, or client not authorized for any of the scopes requested." } in C:\Sources\scripts\script-02\vendor\google\apiclient\src\Http\REST.php:128 Stack trace: #0 C:\Sources\scripts\script-02\vendor\google\apiclient\src\Http\REST.php(103): Google\Http\REST::decodeHttpResponse(Object(GuzzleHttp\Psr7\Response), Object(Gu zzleHttp\Psr7\Request), false) #1 [internal function]: Google\Http\REST::doExecute(Object(GuzzleHttp\Client), O bject(GuzzleHttp\Psr7\Request), false) #2 C:\Sources\scripts\script-02\vendor\google\apiclient\src\Task\Runner.php(182) : call_user_func_array(Array, Array) #3 C:\Sources\scripts\script-02\vendor\google\apiclient\src\Http\REST.php(66): G oogle\Task\Runner->run() #4 C:\Sources\scripts\script-02\vendor\google\apiclient\src\Client.php(898): Goo gle\Http\REST::execute(Object(GuzzleHttp\Client), Object(GuzzleHttp\Psr7\Request ), false, Array, in C:\Sources\scripts\script-02\vendor\google\apiclient\src\Ht tp\REST.php on line 128

    <?php
    require __DIR__ . '/vendor/autoload.php';
    
    
    putenv('GOOGLE_APPLICATION_CREDENTIALS=key\credentials.json');
    
    
    $client = new Google\Client();
    $client->useApplicationDefaultCredentials();
    
    $client->addScope(Google\Service\Drive::DRIVE);
    
    $client->setSubject('[email protected]');
    $service = new Google\Service\Drive($client);
    
    DEFINE("TESTFILE", 'testfile.txt');
    if (!file_exists(TESTFILE)) {
      $fh = fopen(TESTFILE, 'w');
      fseek($fh, 1024*1024*20);
      fwrite($fh, "!", 1);
      fclose($fh);
    }
    
    $file = new Google\Service\Drive\DriveFile();
    $file->name = "Big File";
    $chunkSizeBytes = 1 * 1024 * 1024;
    
    // Call the API with the media upload, defer so it doesn't immediately return.
    $client->setDefer(true);
    $request = $service->files->create($file);
    
    // Create a media file upload to represent our upload process.
    $media = new Google\Http\MediaFileUpload(
        $client,
        $request,
        'text/plain',
        null,
        true,
        $chunkSizeBytes
    );
    $media->setFileSize(filesize(TESTFILE));
    
      // Upload the various chunks. $status will be false until the process is
      // complete.
      $status = false;
      $handle = fopen(TESTFILE, "rb");
      while (!$status && !feof($handle)) {
        // read until you get $chunkSizeBytes from TESTFILE
        // fread will never return more than 8192 bytes if the stream is read buffered and it does not represent a plain file
        // An example of a read buffered file is when reading from a URL
        $chunk = readVideoChunk($handle, $chunkSizeBytes);
        $status = $media->nextChunk($chunk);
      }
    
      // The final value of $status will be the data from the API for the object
      // that has been uploaded.
      $result = false;
      if ($status != false) {
        $result = $status;
      }
    
      fclose($handle);
    
      function readVideoChunk ($handle, $chunkSize)
    {
        $byteCount = 0;
        $giantChunk = "";
        while (!feof($handle)) {
            // fread will never return more than 8192 bytes if the stream is read buffered and it does not represent a plain file
            $chunk = fread($handle, 8192);
            $byteCount += strlen($chunk);
            $giantChunk .= $chunk;
            if ($byteCount >= $chunkSize)
            {
                return $giantChunk;
            }
        }
        return $giantChunk;
    }

I used this, and it's supposed to work from looking at the google results, but reading the documentation itself it seems that they're saying we need to use oAuth. If so, then how can we use the backend to allow anyone to upload to our Google Drive? I don't want someone to log through OAuth to upload files.

https://developers.google.com/drive/api/v3/about-auth

Is there a way to hardcode authentication so that it gets done automatically without the need to go to a link and log in?

2

2 Answers

0
votes

When you create a new project on Google cloud colsome and create client credentials for it. There are a few projec ttypes you can create

  1. web application
  2. installed application
  3. mobile application.
  4. service account

Depending upon which type of credeintals will define which code you will need to use that client.

Client is unauthorized to retrieve access tokens using t his method, or client not authorized for any of the scopes requested

This error message means that you created one type of client but are not using the code that for that client. You appear to be using service account code.

my service account code

The proper code for using a service account would be something like this ServiceAccount.php

require_once __DIR__ . '/vendor/autoload.php';

// Use the developers console and download your service account
// credentials in JSON format. Place the file in this directory or
// change the key file location if necessary.
putenv('GOOGLE_APPLICATION_CREDENTIALS='.__DIR__.'/service-account.json');

/**
 * Gets the Google client refreshing auth if needed.
 * Documentation: https://developers.google.com/identity/protocols/OAuth2ServiceAccount
 * Initializes a client object.
 * @return A google client object.
 */
function getGoogleClient() {
    return getServiceAccountClient();
}

/**
 * Builds the Google client object.
 * Documentation: https://developers.google.com/api-client-library/php/auth/service-accounts
 * Scopes will need to be changed depending upon the API's being accessed. 
 * array(Google_Service_Analytics::ANALYTICS_READONLY, Google_Service_Analytics::ANALYTICS)
 * List of Google Scopes: https://developers.google.com/identity/protocols/googlescopes
 * @return A google client object.
 */
function getServiceAccountClient() {
    try {   
        // Create and configure a new client object.        
        $client = new Google_Client();
        $client->useApplicationDefaultCredentials();
        $client->addScope([YOUR SCOPES HERE]);
        return $client;
    } catch (Exception $e) {
        print "An error occurred: " . $e->getMessage();
    }
}

how to create service account credentials.

I suspect that you did not create a service account client.

Then you be sure that you did in fact make service account credetinals go to google cloud console and follow along with this How to create a service account

0
votes

Are you trying to use a service account with its own credentials or a service account with delegated credentials for a workspace user?

If it is the former, you shouldn't set

$client->setSubject('[email protected]');

If it is the latter, you may not configured domain wide delegation correctly. There is some more information about these error messages here: https://developers.google.com/identity/protocols/oauth2/service-account#error-codes