James Hocking
James Hocking

Reputation: 1

Google Doc API - Access Denied when using a Service Account with Domain Wide Delegation and Scope

I am a super admin of my company's Google Workspace.

And I have written a python script (using the Google Python Client Library) that performs two tasks:

I am using a Service Account with domain wide delegation authority. I have also assigned the following two scopes when granting the domain wide authority to the service account:

I am using with_subject to impersonate the drive owner.

I am able to access a user's drive and documents, albeit read-only, and I can even download non-Google mimetype documents from the impersonated user's drive. However, I receive a 403 permissions denied error (and I promise that this isn't to do with limits) whenever I try to export or save a Google format document, spreadsheet, etc.

An example of my Google document update code is as follows: Very basic, boiler plate:

from google.auth.transport.requests import Request
from google.oauth2.service_account import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError

GOOGLE_KEY_FILE = "google/service_account_credentials.json"

#
SCOPES = [
    "https://www.googleapis.com/auth/drive",
    "https://www.googleapis.com/auth/documents"
]

# ===========================================================================

def get_service_account():
    #
    return Credentials.from_service_account_file(
        GOOGLE_KEY_FILE,
        scopes = SCOPES)
    
def get_subject_credentials(service_account, subject_email):
    return service_account.with_subject(subject_email)

def get_drive_object(subject_credentials):
    service = None
    try:
        service = build("drive", "v3", credentials=subject_credentials)

    except HttpError as error:
        print(f"Error occurred [get_drive_object]: {error}")
    
    return service

def get_document_object(subject_credentials):
    service = None
    try:
        service = build("docs", "v1", credentials=subject_credentials)

    except HttpError as error:
        print(f"Error occurred [get_document_object]: {error}")
    
    return service

# ===========================================================================


def OpenCloseSave(docObject, fileId):
    try:
        # get the document
        """
        document = docObject.documents().get(
            documentId=fileId
        ).execute()
        """
        # modify and save the document
        result = docObject.documents().batchUpdate(
            documentId=fileId,
            body={
                "requests": [{
                    "insertText": {
                        "text": "",
                        "endOfSegmentLocation": {}
                    }
                }]
            }
        ).execute()

        print(f"Result: {result}")

    except HttpError as error:
        print(f"Document error: {error}")

    return 0

# ===========================================================================


def main():

    subjectEmailAddress = "user's email address"
    fileId = "file id from the user's drive"

    serviceAccount = get_service_account()
    if not serviceAccount is None:
        impersonatedUser = get_subject_credentials(serviceAccount, subjectEmailAddress)
        if impersonatedUser is not None:
            documentObject = get_document_object(impersonatedUser)
            #
            OpenCloseSave(documentObject, fileId)

    return 0

if __name__ == "__main__":
    main()
    print("Finished ...")

With the service account that I have created, I can successfully:

However, whenever I try to export a Google document (E.g., doc, spreadsheet) using the Drive API, or try to save a Google Document using the Docs API, I receive a 403 error. Such as:

Document error: <HttpError 403 when requesting https://docs.googleapis.com/v1/documents/<document id>:batchUpdate?alt=json returned "The caller does not have permission". Details: "The caller does not have permission">

If I try to export a Google document using the Drive API, I receive a 403 response and the body content will be HTML similar to a Request Access web page that the Google My Drive presents when an unauthorized user has to request access to a file.

The error is thrown when the execute() function runs on the object returned by the updateBatch function.

In my case, the web page reports that I am signed in as the Impersonated User and that the file is owned by the same user.

Upvotes: 0

Views: 93

Answers (0)

Related Questions