Edit Google calendar events from Google service account: 403 - php

I want to create new event at google calendar from Service Account.
I can access correctly and print a list all my calendars.
But when I want to create a new event the response is 403 Forbidden.
My code:
require_once 'src/Google_Client.php';
require_once 'src/contrib/Google_CalendarService.php';
session_start();
const CLIENT_ID = 'XXXXXXXXXX.apps.googleusercontent.com';
const SERVICE_ACCOUNT_NAME = 'XXXXXXXXXXXX#developer.gserviceaccount.com';
const KEY_FILE = 'google_src/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX-privatekey.p12';
$client = new Google_Client();
$client->setApplicationName("APP_NAME");
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,
'https://www.google.com/calendar/feeds/MY_CALENDAR_ID/private/full/',
$key)
);
$client->setClientId(CLIENT_ID);
$cal = new Google_CalendarService($client);
$event = new Google_Event();
$event->setSummary('Bon dia pel matí!');
$event->setLocation('Somewhere');
$start = new Google_EventDateTime();
$start->setDateTime('2012-08-06T10:00:00.000-07:00');
$event->setStart($start);
$end = new Google_EventDateTime();
$end->setDateTime('2012-09-06T10:25:00.000-07:00');
$event->setEnd($end);
$createdEvent = $cal->events->insert(CALENDAR_NAME, $event);
And server response:
(403) Forbidden
Any ideas? Maybe other scope, or allow edit events (I dont know where I can configure this and I have searched it, promise)
Of course, my calendar is a public calendar.
Any help will be welcome :)
Thanks!

I solved it, and the issue was not code, It works fine.
The problem was sharing my calendar. Something that I don't knew.
To allow edit your calendar events from service account, do not have enough with all steps you do in the Google Api Console, you have to give permission from your calendar configuration (Calendar configuration -> Share this calendar) to the email account specified into Google Api Console (email adress).
This can be a problem if it's a business account, then you will have to contact the account administrator.
The code shown here works correctly, so I hope it helps someone, just remember that you must use 475 version of the Google Api Client.
You can find at this link: http://google-api-php-client.googlecode.com/svn/trunk/src/

Related

Google OAuth2.0 Using PHP and JSON for Service Accounts

I'm trying to use the Google API example to get OAuth2.0 working with my service account, but I'm having trouble with the sample code working without using the Google_Auth_AssertionCredentials since it's been deprecated.
The file is a JSON generated via the Service account page in the developer console.
Here's the snippet of the code.
// Create and configure a new client object.
$client = new Google_Client();
$client->setApplicationName("myApp");
$client->setAuthConfig($key_file_location);
$client->setScopes(Google_Service_Analytics::ANALYTICS);
if($client->isAccessTokenExpired()) {
$client->getRefreshToken();
}
$analytics = new Google_Service_Analytics($client);
Thanks in advance for the help.

Impersonate the user EMAIL ID using Google Oauth2 Credentials ‘Service Account’

I am trying to create Google calendar events using Google Api OAuth service Account from PHP GAE.
I need the correct Session ID or the user EMail ID in the Calendar events field ‘created by’.
This is possible well in Google Apps Script(GAS), it creates the events with the correct session ID.
But, I want the same to be done in PHP GAE(Google App Engine). So, I tried to impersonate the user ID as follows:Perform Google Apps Domain-Wide Delegation of Authority
My aim is to insert the correct user ID of any end user automatically as like in GAS(Google Apps Script). I don't want any default credentials to be set in the field ‘created by’..
Using the PHP client library i tried to impersonate a user in Calendar API.I didn't get any complete sample for Calendar API.So, I tried the Drive API documentation sample, this sample seems to be working fine, Using other domain user also
Using Calendar API I wrote the below example.
<?php
require_once realpath(dirname(__FILE__).'/google-api-php-client-master/src/Google/autoload.php');
require_once realpath(dirname(__FILE__).'/google-api-php-client-master/src/Google/Service/Calendar.php');
require_once realpath(dirname(__FILE__).'/google-api-php-client-master/src/Google/Service/Oauth2.php');
use google\appengine\api\users\User;
use google\appengine\api\users\UserService;
$user = UserService::getCurrentUser();
$userEmail=$user->getEmail();
$client_email = '34234242424-qssjf8kg1kk42dnjdvd2ndrk7rou44#developer.gserviceaccount.com';
$private_key = file_get_contents('key.p12');
$scopes = array('https://www.googleapis.com/auth/calendar');
$credentials = new Google_Auth_AssertionCredentials(
$client_email,
$scopes,
$private_key
);
$credentials->sub = $userEmail;
$client = new Google_Client();
$client->setAssertionCredentials($credentials);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion();
}
$service =new Google_Service_Calendar($client);
$event = new Google_Service_Calendar_Event();
$start = new Google_Service_Calendar_EventDateTime();
$start->setDateTime('2015-09-26T10:00:00.000-07:00');
$event->setStart($start);
$end = new Google_Service_Calendar_EventDateTime();
$end->setDateTime('2015-09-26T10:00:00.000-07:00');
$event->setEnd($end);
$createdEvent = $service->events->insert('abc#group.calendar.google.com', $event);
It’s working well when i check this email, i got the correct service account credentials.
But when i used different email ID, i got this below error
PHP Fatal error: Uncaught exception 'Google_Auth_Exception' with message 'Error refreshing the OAuth2 token, message: '{ "error" : "unauthorized_client", "error_description" : "Unauthorized client or scope in request." }'' in /base/data/home/apps/s~production/1.3874/google-api-php-client-master/src/Google/Auth/OAuth2.php:363 Stack trace: #0 /base/data/home/apps/s~production/1.387/google-api-php-client-master/src/Google/Auth/OAuth2.php(314): Google_Auth_OAuth2->refreshTokenRequest(Array) #1 /base/data/home/apps/s~ei-html-production/1.3874/final.php(34): Google_Auth_OAuth2->refreshTokenWithAssertion() #2 {main} thrown in /base/data/home/apps/s~production/1.38742/google-api-php-client-master/src/Google/Auth/OAuth2.php on line 363
Plz help me what i did wrong.Why the issue happens, when I used diff email ID, my end user who'll create cal events, could be any GMAIL or Google based domain ID.
So, plz help with at least a sample part...
Reference links:
How do I Insert Google Calendar Event using Google Api 3 for any user in the domain?
How to create a Google Calendar event without a reminder / How to get Service Accounts to impersonate users
You can only impersonate users on a google apps domain where you have the necessary permission for (search for 'domain wide delegation'). You've got that covered.
Once you're authorized for impersonation you have to recreate a fresh Google Client for each user you impersonate. You'll only receive an access_token you can use for this very user. If you just change the email address once you're authorized it will not work.

How can I insert data (event) into Google Calendar with PHP?

I am trying to insert events into Google Calendar, but I get errors everytime. I've been searching for hours to get answer, but I found nothing for my problem. I tested a lot of examples, without success. I'm new in Google Calendar, and I can't really understand the google api documentation.
I have a Fullcalendar which uses the Google Calendar (Gcal) as backend. I can read data from Gcal without any problems. When I try to displayed using Fullcalendar, but when I want to write some test datas into Gcal it gives me errors. I want to make a Calendar application which serves as a reservation app. So I have a Calendar, which is displayed to everyone who enter the page, and they can reserve appointments, which are stored in my Google Calendar.
The main is problem is that, I don't really know how to make the connection to Google Calendar for writing data. Every sample I've seen, solves the problem different way, major of them are outdated, some of them uses Sessions, but I don't need Session because the Calendar I want to display is FIX, everyone sees the same.
The code:
require_once 'Google/src/Google/autoload.php';
require_once "Google/src/Google/Client.php";
require_once "Google/src/Google/Service/Calendar.php";
$client_id = 'XXXXXXXXXX-f9ltk86b2klat20k1osmfbgpu4u1vqse.apps.googleusercontent.com';
$client_secret = 'XXXXXXXXXXXXXXXXXXXXXXX';
$key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'; // Server Key
$email_address = 'XXXXXXXXXXXX-f9ltk86b2klat20k1osmfbgpu4u1vqse#developer.gserviceaccount.com';
$client = new Google_Client();
$client->setApplicationName("Calendar");
$client->setClientId($client_id);
$client->setClientSecret($client_secret);
$client->setDeveloperKey($key);
$client->setScopes(array(
'https://www.googleapis.com/auth/plus.login',
));
$cal = new Google_Service_Calendar($client);
$event = new Google_Service_Calendar_Event();
$event->setSummary('Title');
$event->setDescription('Title');
$event->setLocation('Somewhere');
$start = new Google_Service_Calendar_EventDateTime();
$start->setDateTime('2013-08-17T16:00:00.000-07:00');
$event->setStart($start);
$end = new Google_Service_Calendar_EventDateTime();
$end->setDateTime('2013-08-17T17:00:00.000-07:00');
$event->setEnd($end);
$createdEvent = $cal->events->insert('<Calendar ID>', $event);
The exception it generates:
[19-Jun-2015 09:08:59 Europe/Berlin] PHP Fatal error: Uncaught exception 'Google_Service_Exception' with message 'Error calling POST
https://www.googleapis.com/calendar/v3/calendars/hpba8d7p1f6l65ruhbl9qigvks%40group.calendar.google.com/events?key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXX:
(401) Login Required' in
/var/www/XXXXXXXXXXXXXXXXXXXX/calendar/Google/src/Google/Http/REST.php:110
Login Required means that you have not authenticated properly.
By looking at the scope you are using I think that might give you a hint as to why its not working
'https://www.googleapis.com/auth/plus.login'
You are passing the scope for Google+ you should be passing one of the Google calendars scopes if you want to access Google calendar data.
https://www.googleapis.com/auth/calendar read/write access to Calendars
https://www.googleapis.com/auth/calendar.readonly read-only access to Calendars
Authenticate with a service account
<?php
require_once 'Google/autoload.php';
session_start();
/************************************************
The following 3 values an befound in the setting
for the application you created on Google
Developers console. Developers console.
The Key file should be placed in a location
that is not accessable from the web. outside of
web root.
In order to access your GA account you must
Add the Email address as a user at the
ACCOUNT Level in the GA admin.
************************************************/
$client_id = '[your client]';
$Email_address = '[your service account email]';
$key_file_location = '[Your key]';
$client = new Google_Client();
$client->setApplicationName("Client_Library_Examples");
$key = file_get_contents($key_file_location);
// separate additional scopes with a comma
$scopes ="https://www.googleapis.com/auth/calendar";
$cred = new Google_Auth_AssertionCredentials(
$Email_address,
array($scopes),
$key
);
$client->setAssertionCredentials($cred);
if($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
$service = new Google_Service_Calendar($client);
?>
code ripped from tutorial PHP Google Calendar service account
Tip: make sure that you have given the service account access to the calendar in question. You just need to add the service account email to the calendar like you would any other user.

How can I have my server add events to a google calendar using the client library for PHP?

I have very little experience working with the google api and I'm finding it difficult to find relevant information on certain subjects.
What I'm trying to do is create a calendar that requires no log in information from the user. I want my server to add events to the calendar based off of information in a database.
I have gone into my google calendars, created a new one, and worked up some code to add events to the calendar. Then I use the iframe code that google provides to embed the calendar into my site.
The problem I'm running into is that the server wants the user to be logged in as me to add events to the calendar. Since the server is the one adding the events, I'm not really sure how to work around this. I know I need to make/use a service account so my server can "delegate domain-wide authority", but I'm not sure how to do this using the client library for PHP. No examples are provided by google. I had to download a p12 file that my server needs to make these api calls, but I'm not sure how to point to the file using the client library. Is it possible to use the php client library to hook into a service account to make these api calls? If so, how?
Any help is greatly appreciated.
I had the same problem and found the solution (in a round about way) here:
Inserting Google Calendar Entries with Service Account
First thing is to set up your Google calendar correctly (see above mentioned post which describes it very well), then download the API code for the Calendar from here https://github.com/google/google-api-php-client
It's the Download ZIP link on the right of that page.
Then here is some sample code which works for me (private keys replaced with xxxx where appropriate, but otherwise it's exactly what I'm using).
I'm now trying to find out how to read & clear a Google Calendar, which is proving even more challenging!
<?php
//
// built from example at:
// https://stackoverflow.com/questions/26064095/inserting-google-calendar-entries-with-service-account
//
$startdate = new DateTime('2015-01-29 10:00', new DateTimeZone('Europe/London'));
$startdate = $startdate->format('c');
$enddate = new DateTime('2015-01-29 10:00', new DateTimeZone('Europe/London'));
$enddate = $enddate->format('c');
//
// call function to add one event to the calendar (xxxxxxxxxxx#googlemail.com = the calendar owner)
//
calendarize('Test Appointment','Test appt description',$startdate,$enddate,'xxxxxxxxxxx#googlemail.com');
//-----------------------------------------------//
// funtion to add an event to my Google calendar //
//-----------------------------------------------//
function calendarize ($title, $desc, $start_ev_datetime, $end_ev_datetime, $cal_id) {
session_start();
require_once '../google-api-php-client-master/autoload.php';
//Google credentials
$client_id = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com';
$service_account_name = 'xxxxxxxxxxxxxxxxxxxxxxxxxx#developer.gserviceaccount.com';
$key_file_location = '../google-api-php-client-master/API Project-xxxxxxxxxx.p12';
if (!strlen($service_account_name) || !strlen($key_file_location))
echo missingServiceAccountDetailsWarning();
$client = new Google_Client();
$client->setApplicationName("Whatever the name of your app is");
if (isset($_SESSION['service_token'])) {
$client->setAccessToken($_SESSION['service_token']);
}
$key = file_get_contents($key_file_location);
$cred = new Google_Auth_AssertionCredentials(
$service_account_name,
array('https://www.googleapis.com/auth/calendar'),
$key
);
$client->setAssertionCredentials($cred);
if($client->getAuth()->isAccessTokenExpired()) {
try {
$client->getAuth()->refreshTokenWithAssertion($cred);
} catch (Exception $e) {
var_dump($e->getMessage());
}
}
$_SESSION['service_token'] = $client->getAccessToken();
$calendarService = new Google_Service_Calendar($client);
$calendarList = $calendarService->calendarList;
//Set the Event data
$event = new Google_Service_Calendar_Event();
$event->setSummary($title);
$event->setDescription($desc);
$start = new Google_Service_Calendar_EventDateTime();
$start->setDateTime($start_ev_datetime);
$start->setTimeZone('Europe/London');
$event->setStart($start);
$end = new Google_Service_Calendar_EventDateTime();
$end->setDateTime($end_ev_datetime);
$end->setTimeZone('Europe/London');
$event->setEnd($end);
try {
$createdEvent = $calendarService->events->insert($cal_id, $event);
} catch (Exception $e) {
var_dump($e->getMessage());
}
echo 'Event Successfully Added with ID: '.$createdEvent->getId();
}
?>
Using OAuth2 to login and give your server rights to access your calendar account is really simple and well documented (with the google api php client). If you request offline access and store the refresh token, you can log in "as you" server-side at any time.
See Google Accounts Authentication and Authorization: Offline access

google calendar access from the command line

I have activated the google API console https://code.google.com/apis/console and I've created a project, including the OAuth credentials. I've chosen the "desktop application" setting, since this app is going to run outside of the browser, from the CLI (and actually only on my computer).
I have also downloaded the client library as described here: https://code.google.com/p/google-api-php-client/.
I have edited google-api-php-client/src/config.php editing the keys application_name, oauth2_client_id, oauth2_client_secret, oauth2_redirect_uri and developer_key and nothing else.
I have deleted all other services from services too.
Now, I have the following app, put together from the samples in the guide:
<?php
require_once 'google-api-php-client/src/apiClient.php';
require_once "google-api-php-client/src/contrib/apiCalendarService.php";
session_start();
$apiClient = new apiClient();
$apiClient->setUseObjects(true);
$service = new apiCalendarService($apiClient);
if (isset($_SESSION['oauth_access_token'])) {
$apiClient->setAccessToken($_SESSION['oauth_access_token']);
} else {
$token = $apiClient->authenticate();
$_SESSION['oauth_access_token'] = $token;
}
$event = new Event();
$event->setSummary('Appointment');
$event->setLocation('Somewhere');
$start = new EventDateTime();
$start->setDateTime('2011-06-03T10:00:00.000-07:00');
$start->setTimeZone('America/Los_Angeles');
$event->setStart($start);
$end = new EventDateTime();
$end->setDateTime('2011-06-03T10:25:00.000-07:00');
$end->setTimeZone('America/Los_Angeles');
$event->setEnd($end);
$event->setRecurrence(array('RRULE:FREQ=WEEKLY;UNTIL=20110701T100000-07:00'));
$attendee1 = new EventAttendee();
$attendee1->setEmail('attendeeEmail');
// ...
$attendees = array($attendee1,
// ...
);
$event->attendees = $attendees;
$recurringEvent = $service->events->insert('primary', $event);
echo $recurringEvent->getId();
However I'm getting the following error:
Fatal error: Uncaught exception 'apiServiceException' with message 'Error calling POST https://www.googleapis.com/calendar/v3/calendars/primary/events?key=<the-key>: (401) Login Required' in /home/flav/projects/.../google-api-php-client/src/io/apiREST.php on line 86
apiServiceException: Error calling POST https://www.googleapis.com/calendar/v3/calendars/primary/events?key=<the-key>: (401) Login Required in /home/flav/projects/.../google-api-php-client/src/io/apiREST.php on line 86
Call Stack:
0.0003 252600 1. {main}() /home/flav/projects/.../gcal-api.php:0
0.0202 1769344 2. EventsServiceResource->insert() /home/flav/projects/.../gcal-api.php:38
0.0202 1770288 3. apiServiceResource->__call() /home/flav/projects/.../google-api-php-client/src/contrib/apiCalendarService.php:493
0.0206 1781864 4. apiREST::execute() /home/flav/projects/.../google-api-php-client/src/service/apiServiceResource.php:187
0.2342 1794848 5. apiREST::decodeHttpResponse() /home/flav/projects/.../google-api-php-client/src/io/apiREST.php:56
How to fix this?
Oh, and on the google API console, I have two values for Redirect URIs:, urn:ietf:wg:oauth:2.0:oob and http://localhost, which one should I use for oauth2_redirect_uri?
I think this can be caused by several things. my 2 cents:
Do you have several calendars registered? Maybe your calendar which you'd like to insert events into isn't the "primary" (=default?) calendar (or your Oauth cred data refer to a different calendar).
If so, replace this line
$service->events->insert('primary', $event);
with
$calendar_id = "somelongstring#group.calendar.google.com"; //look this up from calendar /settings calendar details settings page at the bottom
$service->events->insert($calendar_id, $event);
The calendar id is a bit hard to find...look it up. You can find it, for example, on your google account home page /calendar /gear symbol /settings / click calendar-name / calendar details settings page, at the bottom.
My redirect url (for a web app, though) points to the .php page that issued the oauth request. If authenticated I define another redirect, this time my own. Confusing? yes, but it works for me.

Categories