Developers & Practitioners

Don't fear the authentication: Google Drive edition

Header

There are times when I’m building an application on GCP when I don’t want to use a more traditional datastore like Cloud SQL or Bigtable. Right now, for example, I’m building an app that allows non-technical folks to easily add icons into a build system. I’m not going to write a front-end from scratch, and teaching them source control, while valuable, isn’t really something I wanted to tackle right now. So an easy solution is to use Google Drive. Maybe you never thought of it as a data store...but let’s talk about it here for a minute. Super simple interface, has rudimentary source control built into it, and it has an API so I can automate pulling the icons from Drive into proper source control and our build system for everyone to consume the icons!

Only one problem...and I have a confession to make. I hate OAuth, and on the surface it seems like you need to use OAuth in order to use Google Drive’s API. Okay okay, hate is probably too strong of a word. I don’t hate what it does. I recognize that it’s hugely important. I just don’t like that since it’s not something I use every day, I can never remember exactly what I need to do. I need which token from where now? And do I put it in a header? What’s the name of the header? I’m always looking up how to implement OAuth correctly each time I have to do it.

Now, what IS in my day to day sweetspot? Working with service accounts and IAM within GCP for authorization. So it turns out...if you want to integrate Google Drive functionality into your application that already uses GCP services, you can totally use IAM service accounts to do it!

The key to this magic is to understand that IAM service accounts are also users. And users have email addresses. If you look at a service account in the list on the access page in the console:

service account

That email address is the magic. Just as you can share a Drive folder with a person, you can also share a Drive folder with an IAM service account. Or a Sheet, or a Doc. Whatever it is you want to integrate into your GCP application. 

So in my case, I needed to share the Drive folder where our marketing folks were going to put the icons. Let’s walk through what I did to get it working. I created a service account in the console here. Click the Create Service Account button up at the top. Give it a name, grant it account access to what roles the application needs for the GCP services you’re using. Drive itself doesn’t actually need a specific permission role. So for example, if the application needs to also be able to write entries into a Cloud SQL database as well as access the Drive content, then you’d need to give it the Cloud SQL Client role. Only add the permissions you need. Do not give blanket “Owner” permissions please.

When you’re done, click into the details of your service account in the list, and click “Add Key”

keys

Pick the JSON type, and it will download the bearer token for that service account. PLEASE be careful with it. It’s a bearer token, which means anyone that has it now has permission to do stuff in your project based on the permissions you gave the service account. For example, writing to or reading from the database if you gave it the Cloud SQL Client role. This is why you only want to give it the specific roles you want, and not Owner level permissions.

The code, in Python, looks like this:

Language: Python

  from googleapiclient.discovery import build
from google.oauth2 import service_account
from googleapiclient.errors import HttpError as HTTPError

SCOPES = ['https://www.googleapis.com/auth/drive']

sa_creds = service_account.Credentials.from_service_account_file('drive_icons_sa.json')
scoped_creds = sa_creds.with_scopes(SCOPES)
drive_service = build('drive', 'v3', credentials=scoped_creds)

If you aren’t familiar, the discovery APIs are wrappers on the REST APIs in native languages, like Python. Finding all of what you can do with the API is a little bit all over the place depending on what you want to do. A good place to start is here, which walks through the basics of Drive APIs, like creating folders and files, downloading, searching, etc. For example, grabbing all the folders in a Drive folder would be:

  children = drive_service.files().list(q=f"mimeType = 'application/vnd.google-apps.folder' and '{marketing_icon_folder_id}' in parents", fields='files(name, id)').execute()

That will fetch the first 100 folders (pageSize is 100 by default, you can change it by adding another parameter pageSize=n to the list call) in our marketing_icon_folder_id, giving us the names and Drive ids of those folders.

So that’s it. A nice quick way to avoid having to remember how to set up OAuth when you want to use Google Drive as a data store with a simple UI, basic versioning, and fully-featured APIs for your GCP-integrated application. Thanks for reading, hopefully it helps! 

If you’re looking for ideas for things to create, we have a number of codelabs that might spark some fun ideas here. If you have questions, or you want to tell me what cool things you’re doing with Drive and GCP, reach out to me on Twitter, my DMs are open.