Search code examples
c#google-apigoogle-drive-shared-drive

How to view Google shared drive from web and api 3.0 service account


I want my C# console app to be able to upload files using a service account to a Google shared drive as well as download / delete these files when logging in to the Google web UI under my personal account. It is my understanding that an oauth account is not necessary and I can do this with only a service account.

Thus far, I have:

  1. Created a Google Drive API and a service account.
  2. Created a Google Shared Drive and assigned my service account as a "manager".

The console app can upload files and get a list of files that it uploaded but cannot see the shared folder or files that are shared to the service account email.

Google Shared Drive and permissions

Google domain wide delegation

This will get a Google Drive Service successfully but I think the problem may be in the impersonation / delegation.

        private DriveService GetDriveService()
        {
            // Load the Service Account JSON key file
            string rootDirectory = Environment.CurrentDirectory;
            string keyFilePath = rootDirectory + "\\mykey.json";

            ServiceAccountCredential? credential;

            using (var stream = new FileStream(keyFilePath, FileMode.Open, FileAccess.Read))
            {
                credential = GoogleCredential.FromStream(stream)
                    .CreateScoped(DriveService.Scope.Drive)
                    .CreateWithUser("[email protected]") // Specifying the user to impersonate
                    .UnderlyingCredential as ServiceAccountCredential;
            }

            // Specify the scopes required
            var scopes = new[] { DriveService.Scope.DriveFile };

            // Create a delegated credential
            if (credential == null) throw new ArgumentNullException(nameof(credential));

            var delegatedCredential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(credential.Id)
            {
                Key = credential.Key,
                Scopes = scopes
            });

            // Create the Drive service
            var driveService = new DriveService(new BaseClientService.Initializer
            {
                HttpClientInitializer = delegatedCredential,
                ApplicationName = "ServerTools"
            });

            return driveService;
        }

This code will successfully get a list of files that were uploaded by the console app but they don't show up in the Web UI.

        public List<string> GetFileList()
        {
            var request = _driveService.Files.List();
            request.Fields = "nextPageToken, files(id, name)";

            var files = request.Execute().Files;

            return files.Select(x => x.Name).ToList();
        }

This code will not return any folders even though a shared drive is created and the service account is a manager

        private List<string>? GetFolders()
        {
            FilesResource.ListRequest listRequest = _driveService.Files.List();
            listRequest.Q = "mimeType='application/vnd.google-apps.folder'";
            listRequest.Fields = "nextPageToken, files(id, name)";

            // List files.
            IList<Google.Apis.Drive.v3.Data.File> files = listRequest.Execute().Files;

            return files.Select(x => x.Name).ToList();

        }

This feels like a configuration issue but I have run out of places to look. Thanks in advance!


Solution

  • Although I'm not sure whether I could correctly understand your question, how about the following modification? Please modify your bottom script as follows.

    From:

    FilesResource.ListRequest listRequest = _driveService.Files.List();
    listRequest.Q = "mimeType='application/vnd.google-apps.folder'";
    listRequest.Fields = "nextPageToken, files(id, name)";
    

    To:

    FilesResource.ListRequest listRequest = _driveService.Files.List();
    listRequest.Q = "mimeType='application/vnd.google-apps.folder'";
    listRequest.Fields = "nextPageToken, files(id, name)";
    listRequest.Corpora = "allDrives"; // Added
    listRequest.SupportsAllDrives = true; // Added
    listRequest.IncludeItemsFromAllDrives = true; // Added
    // listRequest.PageSize = 1000; // Add this if you want.
    
    • I guessed that in your current script, only the folders in the drive of the service account are trying to be retrieved. In this modification, the folders are searched from all drives including the shared drives that the service account can access.

    Reference: