Skip to content

Instantly share code, notes, and snippets.

@lewisrodgers
Last active April 9, 2024 09:50
Show Gist options
  • Save lewisrodgers/fa766ebd37c1397d3a014eb73805edd1 to your computer and use it in GitHub Desktop.
Save lewisrodgers/fa766ebd37c1397d3a014eb73805edd1 to your computer and use it in GitHub Desktop.
Python boilerplate for service account oauth setup to return data from a Google API

Prerequisites

For a more detailed version of the steps below visit: https://developers.google.com/admin-sdk/directory/v1/guides/delegation

  • Enable the necessary APIs (calendar, drive, gmail, etc.) in Cloud Console
  • Create a service account, download the json key file, and enable domain wide delegation (DwD)
  • Determine the required scopes (calendar readonly, drive read/write, etc.)
  • In the G Suite console, an admin authorizes the service account (client ID) with the specified scopes
  • The admin also identifies an account — with proper admin privileges — that the service account will impersonate (when you want to access user's data without manual authorization from the user)

With the above in place, you or another developer, who has the json key file, can run the python code.

For documentation on how to do with Java see: https://developers.google.com/api-client-library/java/google-api-java-client/oauth2#service_accounts

Errors

"unauthorized_client: Client is unauthorized to retrieve access tokens using this method."

Most likely means the service account hasn't been authorized in the G Suite console properly. Check that the scopes are the same between the app and G Suite.

"Not Authorized to access this resource/api"

The delegate user account doesn't have proper privileges to access the requested resource. https://stackoverflow.com/questions/42784640/client-is-unauthorized-to-retrieve-access-tokens-using-this-method-gmail-api-c-s

Gmail API returns 403 error code and “Delegation denied for...”

https://stackoverflow.com/questions/26135310/gmail-api-returns-403-error-code-and-delegation-denied-for-user-email

# pip install --upgrade google-api-python-client google-auth google-auth-httplib2
from google.oauth2 import service_account
import googleapiclient.discovery
SCOPES = ['https://www.googleapis.com/auth/admin.directory.user.readonly']
SERVICE_ACCOUNT_FILE = 'credentials.json'
DELEGATE='<admin@domain.com>' # Service account will impersonate this user. Must have proper admin privileges in G Suite.
TARGET='<domain.com>' # Service account wants to access data from this.
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
credentials_delegated = credentials.with_subject(DELEGATE)
service = googleapiclient.discovery.build('admin', 'directory_v1', credentials=credentials_delegated)
response = service.users().list(domain=TARGET).execute()
print(response)
# pip install --upgrade google-api-python-client google-auth google-auth-httplib2
from google.oauth2 import service_account
import googleapiclient.discovery
SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']
SERVICE_ACCOUNT_FILE = 'credentials.json' # path to json key file generated after creating a service account with DwD enabled.
TARGET='<user@domain.com>' # Service account wants to access data from this.
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
service = googleapiclient.discovery.build('calendar', 'v3', credentials=credentials)
response = service.calendars().get(calendarId=TARGET).execute()
print(response)
# pip install --upgrade google-api-python-client google-auth google-auth-httplib2
from google.oauth2 import service_account
import googleapiclient.discovery
SCOPES = ['https://www.googleapis.com/auth/drive.readonly']
SERVICE_ACCOUNT_FILE = 'credentials.json'
DELEGATE='<admin@domain.com>' # Service account will impersonate this user. Must have proper admin privileges in G Suite.
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
credentials_delegated = credentials.with_subject(DELEGATE)
service = googleapiclient.discovery.build('drive', 'v3', credentials=credentials_delegated)
response = service.files().list(corpus='domain').execute()
print(response)
@alberto-clara
Copy link

Very helpful to get started with the admin-api with service accounts. Thank you.

@DmitryIvanoff
Copy link

saved my time

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment