timkly timkly - 1 year ago 482
C# Question

Google Drive API - Transfer ownership from Service Account

I am attempting to transfer ownership from a Service Account created document to another user who resides within the same Google Apps account using the code below but am getting the following error

The resource body includes fields which are not directly writable. [403]
Errors [Message[The resource body includes fields which are not directly writable.] Location[ - ] Reason[fieldNotWritable] Domain[global]]

var service = GetService();

var permission = GetPermission(fileId, email);
permission.Role = "owner";

var updatePermission = service.Permissions.Update(permission, fileId, permission.Id);
updatePermission.TransferOwnership = true;
return updatePermission.Execute();
catch (Exception e)
Console.WriteLine("An error occurred: " + e.Message);
return null;

Commenting out // permission.Role = "owner"; returns the error below

The transferOwnership parameter must be enabled when the permission role is 'owner'. [403] Errors [Message[The transferOwnership parameter must be enabled when the permission role is 'owner'.] Location[transferOwnership - parameter] Reason[forbidden] Domain[global]]

Assigning any other permissions works fine. Therefore, is this a limitation of the Service Account not being able to transfer ownership to any other account that doesn't use the @gserviceaccount.com email address (i.e. our-project@appspot.gserviceaccount.com > email@domain.com)?

The email@domain.com email address has been created and is managed within Google Apps.

In the case, it is not achievable, any pointers on where to look next? We need multiple users to have the ability to create documents ad hoc and assign permissions and transfer ownership on the fly via the API.


Answer Source

I have found the answer and am posting for anyone else who comes across this question.

  1. You can not use the 'Service Account Key JSON file' as recommended by Google.
  2. You need to use the p.12 certificate file for authentication.
  3. The code to create a drive service for mimicking accounts is as follows.

    public DriveService GetService(string certificatePath, string certificatePassword, string googleAppsEmailAccount, string emailAccountToMimic, bool allowWrite = true)
        var certificate = new X509Certificate2(certificatePath, certificatePassword, X509KeyStorageFlags.Exportable);
        var credential = new ServiceAccountCredential(
           new ServiceAccountCredential.Initializer(googleAppsEmailAccount)
               Scopes = new[] { allowWrite ? DriveService.Scope.Drive : DriveService.Scope.DriveReadonly },
               User = emailAccountToMimic
        // Create the service.
        return new DriveService(new BaseClientService.Initializer
            HttpClientInitializer = credential,
            ApplicationName = ApplicationName
  4. You need to follow the steps listed here to delegate domain-wide authority to the service account.

  5. Allow 5 to 10 minutes after completing step 4.
  6. You can now create documents under the 'emailAccountToMimic' user which sets them to be the owner during creation.