Search code examples
google-apigoogle-api-php-clientservice-accountsgoogle-calendar-apigoogle-workspace

Google Service to Service Authentication Not Working


I'm attempting to have my php application call Google's Calendar API using the service to service authentication. I have administrative access over my Education G Suite, and have performed the following steps as indicated here: https://developers.google.com/identity/protocols/OAuth2ServiceAccount

  1. Created a service account with domain-wide authority, and saved the proper credentials.
  2. Added the Calendar (Read-Write) https://www.googleapis.com/auth/calendar scope to my admin account under "Managed API Client Access" using my ClientID (which is confirmed by the UI)
  3. Made the proper calls to the php API client, attempting to both impersonate the admin and another user account, per the examples here: https://developers.google.com/api-client-library/php/auth/service-accounts

However, when I attempt to obtain any calendar information I continue to get the following error:

Google_Service_Exception: { "error": "unauthorized_client", "error_description": "Client is unauthorized to retrieve access tokens using this method." }

Per googling, this would typically mean that I haven't delegated domain-wide authority, but I definitely have. I've tried other Google apis with the same results.

Here's my code. Thanks for any thoughts or help.

<?php require_once __DIR__ . '/vendor/autoload.php';
putenv('GOOGLE_APPLICATION_CREDENTIALS=****/client_secret.json');

$user_to_impersonate = 'user@****.com';
$user_scopes = array(
    Google_Service_Calendar::CALENDAR
);
$client = new Google_Client();
$client->useApplicationDefaultCredentials();
$client->setSubject($user_to_impersonate);
$client->setScopes($user_scopes);
$client->setAccessType('offline');

$calendar = new Google_Service_Calendar($client);
$calendarId = 'primary';
$optParams = array(
    'maxResults' => 10,
    'orderBy' => 'startTime',
    'singleEvents' => TRUE,
    'timeMin' => date('c'),
);
$results = $calendar->events->listEvents($calendarId, $optParams);
...


?>

Solution

  • Client is unauthorized to retrieve access tokens using this method.

    When you create your project on Google developer console you should have created service account credentials. You would then be promoted to download a file this file contains the credentials for a service account.

    The code you use to connect to a service account is different then the code use to connect using browsers or native client credentials.

    ServiceAccount.php link to code

    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();
        }
    }
    

    You appear to be using the correct service account code. However you have probably downloaded the wrong credentials file i suggest you download the file from Google developer console again.