Tuesday, December 3, 2013

Google Drive API - How to work with the domain-wide service account

I was trying to use the service account of my app to access to all documents of all users in my domain following this instruction:


But it didn't work.

This afternoon, my college showed me the old interface of the Google API Console which is different from the above one. So, I tried to create a service account using this page:


The old interface allows me to create a service account which results in these following information:

+ A private key file (to download right after I created the service account)
+ Client ID
+ Email adress

Next, I will add the above Client ID to the Admin Console of my domain admin interface, and assign google drive api access for my app's service account with scope:


After that, I can use the service account (private key and email address) to access to all the documents of all users in my domain.

import httplib2

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

# Copy your credentials from the console
CLIENT_ID = '<my_client_id>.apps.googleusercontent.com'

"""Email of the Service Account"""
SERVICE_ACCOUNT_EMAIL = '<my_service_account_email>@developer.gserviceaccount.com'

"""Path to the Service Account's Private Key file"""
SERVICE_ACCOUNT_PKCS12_FILE = '<my private key>-privatekey.p12'

# Check https://developers.google.com/drive/scopes for all available scopes
OAUTH_SCOPE = 'https://www.googleapis.com/auth/drive'

# domain-wide
def create_drive_service(service_account_pkcs12_file, service_account_email, scope, user_email):
    """Build and returns a Drive service object authorized with the service accounts
        that act on behalf of the given user.

        user_email: The email of the user.
        Drive service object.
    f = file(service_account_pkcs12_file, 'rb')
    key = f.read()

    credentials = SignedJwtAssertionCredentials(service_account_email, key,
                            scope=scope, sub=user_email)
    http = httplib2.Http()
    http = credentials.authorize(http)

    return build('drive', 'v2', http=http)

def retrieve_all(service):
    """Retrieve a list of File resources.

    service: Drive API service instance.
    List of File resources.

    result = []
    page_token = None
    while True:
            param = {}
            if page_token:
                param['pageToken'] = page_token
            files = service.files().list(**param).execute()

            page_token = files.get('nextPageToken')
            if not page_token:
        except errors.HttpError, error:
            print 'An error occurred: %s' % error

    return result

if __name__ == "__main__":

    user_email = 'trinh@mydomain.com'
    service = create_drive_service(SERVICE_ACCOUNT_PKCS12_FILE, SERVICE_ACCOUNT_EMAIL, OAUTH_SCOPE, user_email)
    allfiles = retrieve_all(service)
    print allfiles[0]['title']

Updated source code: https://github.com/dangtrinh/gdm


References: This is google+ docs but applicable for drive: https://developers.google.com/+/domains/authentication/delegation