Google Drive API with Service Account in Python

Google Drive API with Service Account in Python

If you need to access your files from a program in Google Drive without needing you to authenticate yourself, that is, a machine-to-machine communication, then you will need to set up a service account.

Creating a service account

To create a service account, first, you need to create a project in the google cloud platform to associate the account with, go to the google cloud console, if it is the first time you are accessing it, you will need to accept the Terms of Service, once there, at the top-left, click Menu ☰ > IAM & Admin > Create a Project, enter a project name, optionally edit the project ID and click create.

Once the project is created, we need to enable the APIs that we want to access, in this case, Google Drive API, click Menu ☰ > APIs & Services> Library, search for Google Drive API, and select it, in the next screen, click enable.

The next step is to create the service account, click Menu ☰ > IAM & Admin > Service Accounts, click Create service account, enter the service account name and ID, click Create and continue, optionally select roles, we can leave it blank, click Continue and Done. Now select the recently created account by clicking on the email, go to the Keys tab, click Add key > Create new key, select JSON and click Create, make sure to store the file securely as this is the only copy of the key.

Install the dependencies

Install the required dependencies as below:

pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib

Depending on your operating system, installing the dependencies may be different, for example, in archlinux, many popular packages can be installed system-wide with pacman:

pacman -S python-google-api-python-client python-google-auth-oauthlib

Implementation

Create a python file in a working directory, for example, googledrive.py, and copy the downloaded json key to this directory as well.

These are the required imports:

from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from google.oauth2 import service_account

We can define a generic function to create a Google API service authenticated with credentials from a service account:

def get_service(api_name, api_version, scopes, key_file_location):
    """Get a service that communicates to a Google API.

    Args:
        api_name: The name of the api to connect to.
        api_version: The api version to connect to.
        scopes: A list auth scopes to authorize for the application.
        key_file_location: The path to a valid service account JSON key file.

    Returns:
        A service that is connected to the specified API.
    """

    credentials = service_account.Credentials.from_service_account_file(
    key_file_location)

    scoped_credentials = credentials.with_scopes(scopes)

    # Build the service object.
    service = build(api_name, api_version, credentials=scoped_credentials)

    return service

For other ways to authenticate with google APIs with python, see this documentation.

In the main function, we define the location of our key file and the scopes we would like to use with the service, in this case, “https://www.googleapis.com/auth/drive.metadata.readonly”, the complete list of scopes for google drive API v3 can be found here.

We call the get_service function with ‘drive’ and ‘v3’ as api_name and api_version, along with the scopes and the key file location, now with the service object, we can do different operations like listing the files:

def main():
    """Shows basic usage of the Drive v3 API.
    Prints the names and ids of the first 10 files the user has access to.
    """

    # Define the auth scopes to request.
    scope = 'https://www.googleapis.com/auth/drive.metadata.readonly'
    key_file_location = 'wallet-exporter-455d1f2cb62d.json'

    try:
        # Authenticate and construct service.
        service = get_service(
            api_name='drive',
            api_version='v3',
            scopes=[scope],
            key_file_location=key_file_location)

        # Call the Drive v3 API
        results = service.files().list(
            pageSize=10, fields="nextPageToken, files(id, name)").execute()
        items = results.get('files', [])

        if not items:
            print('No files found.')
            return
        print('Files:')
        for item in items:
            print(u'{0} ({1})'.format(item['name'], item['id']))
    except HttpError as error:
        # TODO(developer) - Handle errors from drive API.
        print(f'An error occurred: {error}')

if __name__ == '__main__':
    main()

If you run the script and you get the “No files found.” output is because you have not shared any files with the service account.

$ python googledrive.py 
No files found.

You will need to share the files and folders you would like to have access to from your script with the service account’s email.

In the google cloud console, go to Menu ☰ > IAM & Admin > Service Accounts, and copy the service account’s email.

If you run the script again, you should see a different output now, for example:

$ python googledrive.py 
Files:
blog (1I3f0K...)
File 2 (1_Oul...)
File 1 (1PUMY...)

The complete code can be found here.