Search code examples
google-calendar-apigoogle-api-python-client

Google Calendar Python API with service account returning no results


I'm trying to download a list of Google calendars my user can see. I've got a service account set up, and I've got this code (which works for a different account for the Analytics API):

from apiclient.discovery import build
from oauth2client.client import SignedJwtAssertionCredentials
import pprint

def prepare_credentials():
    f = file(keyFilePath, 'rb')
    key = f.read()
    f.close()
    credentials = SignedJwtAssertionCredentials(
        service_account_email_address, key,
        scope='https://www.googleapis.com/auth/calendar.readonly')
    return credentials
http = httplib2.Http()
credentials = prepare_credentials()
http = credentials.authorize(http)
service = build('calendar', 'v3', http=http)
httpRequest = service.calendarList().list()
data = httpRequest.execute()
pprint.pprint(data)

Which results in:

{u'etag': u'"YXs7dfDSFSFD9F0k/sofIhuT4dSLyxKaRH7vNpx5BOEU"',
u'items': [],
u'kind': u'calendar#calendarList',
u'nextSyncToken': u'00001405024697194000'}

The thing is, I know I have access to calendars, and I've even used the "Try It!" section of this page: https://developers.google.com/google-apps/calendar/v3/reference/calendarList/list, which returns the expected results, about 10 calendars. I've tried different versions of the scope parameter ('https://www.googleapis.com/auth/calendar.readonly', and ['https://www.googleapis.com/auth/calendar','https://www.googleapis.com/auth/calendar.readonly']), and I've also tried adding my own email address as both the "prn" and "sub" parameters, all of which give me "access denied" errors. I can't figure out why I can get authorized with my service account, but am unable to actually view the results, when those results are clearly viewable with a different authentication method.

What am I doing wrong?


Solution

  • Just wanted to update this question with the solution I actually ended up going with.

    If you want a service account to be able to have owner privileges on a calendar, it appears as though the only way to do this is to use the API to create a secondary calendar while authenticated as the service account (https://developers.google.com/google-apps/calendar/v3/reference/calendars/insert). The service account does not have any primary calendars it is the owner of, but it will be the owner of the new secondary calendar.

    You can then use the Access Control Rules API endpoint (https://developers.google.com/google-apps/calendar/v3/reference/acl/insert) to share this calendar with your own Google account (or any non-service account that can log in to view the calendar in a browser). The new user can also be set as the owner.

    Edit: The solution below is not accurate.

    This wasn't in the question, but I couldn't find it anywhere and I think people will probably want to know, so I'll answer it here too:

    If you want the attendees to receive an email notification when you insert or update an event, setting the 'sendNotifications' parameter to True is not the only thing you need to do. After sharing the calendar with that user, the user also needs to go into "Calendar settings" for your service account's calendar and activate email notifications in the "Reminders and Notifications" tab.

    Edit: This is inaccurate. Anyone who changes their settings to receive notifications on this calendar will receive them regardless of whether they've been invited to the event. I have not found a way to invite people to an event via the API with a service account and have only the invitees receive an invitation email. I will ask another question on StackOverflow about this.