OAuth2 token, message: '{ "error" : "access_denied" }' returned when I try to update Google Calendar using OAuth (Service Account)

Roydon D' Souza picture Roydon D' Souza · Mar 1, 2013 · Viewed 12.6k times · Source

I am using Google Standard Library for PHP for using Calendar Service and I have set up a Service Account type for OAuth 2.0 Authentication through Google API Console.

My main objective is to update the user's google calendar (eg: [email protected]) (when user is not online) through a batch. Eg. updating an event in the users calendar.

When the user logs in the application (using OAuth2.0) he/she will provide permission for the application to "Manage your calendars","View your calendars" and to "Perform these operations when I'm not using the application"

Following code is used to login using OAuth2.0

<?php
require_once '../../src/Google_Client.php';
require_once '../../src/contrib/Google_CalendarService.php';
session_start();

$client = new Google_Client();
$client->setApplicationName("Google Calendar PHP Starter Application");


$client->setClientId('XXXXX-flue2a9o5ll602ovrhaejlpm9otgjh1r.apps.googleusercontent.com');
$client->setClientSecret('XXXXXXXXXX');
$client->setRedirectUri('http://localhost/testAPI/google-api-php-client/examples/calendar/simple.php');
$client->setDeveloperKey('AIzaSyCGvXRXGMo58ZDswyb4zBkJgRMLcHBRIrI');
$cal = new Google_CalendarService($client);
if (isset($_GET['logout'])) {
  unset($_SESSION['token']);
}

if (isset($_GET['code'])) {
  $client->authenticate($_GET['code']);

  $_SESSION['code']=$_GET['code'];

  $_SESSION['token'] = $client->getAccessToken();
  header('Location: http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']);
}

if (isset($_SESSION['token'])) {
  $client->setAccessToken($_SESSION['token']);
}

if ($client->getAccessToken()) {
  $calList = $cal->calendarList->listCalendarList();
  print "<h1>Calendar List</h1><pre>" . print_r($calList, true) . "</pre>";

  echo $_SESSION['code'];


$_SESSION['token'] = $client->getAccessToken();
} else {
  $authUrl = $client->createAuthUrl();
  print "<a class='login' href='$authUrl'>Connect Me!</a>";
}

?>

Once I get permissions do I have to save something to use these permissions in future when the user is not logged in?

Following code works fine when user is logged in. But returns Error refreshing the OAuth2 token, message: '{ "error" : "access_denied" }' when user is logged out

<?php 

require_once '../src/Google_Client.php';
require_once '../src/contrib/Google_CalendarService.php';

session_start();

const CLIENT_ID = 'XXXXXX.apps.googleusercontent.com';
const SERVICE_ACCOUNT_NAME = '[email protected]';

const KEY_FILE = 'f183b8caXXXXXXXXatekey.p12';

$client = new Google_Client();
$client->setApplicationName("XXXXXXXX Calendar Service");

if (isset($_SESSION['token'])) {
 $client->setAccessToken($_SESSION['token']);
}

$key = file_get_contents(KEY_FILE);
$client->setClientId(CLIENT_ID);

$client->setAssertionCredentials(new Google_AssertionCredentials(
        SERVICE_ACCOUNT_NAME,
        array('https://www.googleapis.com/auth/calendar'),
        $key,
        'notasecret',
        'http://oauth.net/grant_type/jwt/1.0/bearer',
        '[email protected]')
);

$client->setClientId(CLIENT_ID);

$cal = new Google_CalendarService($client);

    try{
$cal->events->quickAdd("[email protected]", "SERVICE TEST ");
}catch(Exception $e){

    print_r($e->getMessage());
}

// We're not done yet. Remember to update the cached access token.
// Remember to replace $_SESSION with a real database or memcached.
if ($client->getAccessToken()) {
    echo $_SESSION['token'] = $client->getAccessToken();
}

What should I do in order to update calendar when user is not logged in (provided user has given permission). Should I save the Access Code when user is logged in and use it later when I want to run the batch?

BTW What is association handle?

Answer

Alan picture Alan · Mar 5, 2013

In fact you do not need to share the calendar with the service account. What needs to happen is to Delegate domain-wide authority to your service account.

The service account that you created now needs to be granted access to the Google Apps domain’s user data that you want to access.

The following tasks have to be performed by an administrator of the Google Apps domain: 1. Go to your Google Apps domain’s control panel. The URL should look like: https://www.google.com/a/cpanel/mydomain.com

  1. Go to Advanced tools... > Manage third party OAuth Client access.

  2. In the Client name field enter the service account's Client ID.

  3. In the One or More API Scopes field enter the list of scopes that your application should be granted access to. For example if you need domain-wide readonly access to the Google Calendar API enter: https://www.googleapis.com/auth/calendar.readonly

  4. Click the Authorize button.