Share files, folders, and drives

Every Google Drive file, folder, and shared drive have associated permissions resources. Each resource identifies the permission for a specific type (user, group, domain, anyone) and role (owner, organizer, fileOrganizer, writer, commenter, reader). For example, a file might have a permission granting a specific user (type=user) read-only access (role=reader) while another permission grants members of a specific group (type=group) the ability to add comments to a file (role=commenter).

For a complete list of roles and the operations permitted by each, refer to Roles and permissions.

Scenarios for sharing Drive resources

There are five different types of sharing scenarios:

  1. To share a file in My Drive, the user must have role=writer or role=owner.

  2. To share a folder in My Drive, the user must have role=writer or role=owner.

    • If the writersCanShare boolean value is set to false for the file, the user must have the more permissive role=owner.

    • Temporary access (governed by an expiration date and time) isn't allowed on My Drive folders with role=writer. For more information, see Set an expiration date to limit file access.

  3. To share a file in a shared drive, the user must have role=writer, role=fileOrganizer, or role=organizer.

    • The writersCanShare setting doesn't apply to items in shared drives. It's treated as if it's always set to true.
  4. To share a folder in a shared drive, the user must have role=organizer.

    • If the sharingFoldersRequiresOrganizerPermission restriction on a shared drive is set to false, users with role=fileOrganizer can share folders in that shared drive.
  5. To manage shared drive membership, the user must have role=organizer. Only users and groups can be members of shared drives.

Set an expiration date to limit file access

When you're working with people on a sensitive project, you might want to restrict their access to certain files in Drive after a period of time. For files in My Drive, you can set an expiration date to limit or remove access to that file.

To set the expiration date:

The expirationTime field denotes when the permission expires using RFC 3339 date-time. Expiration times have the following restrictions:

  • They can only be set on user and group permissions.
  • The time must be in the future.
  • The time cannot be more than a year in the future.

For more information about expiration date, see the following articles:

Permission propagation

Permission lists for a folder propagate downward, and all child files and folders inherit permissions from the parent. Whenever permissions or the hierarchy is changed, the propagation occurs recursively through all nested folders. For example, if a file exists in a folder and that folder is then moved within another folder, the permissions on the new folder propagate to the file. If the new folder grants the user of the file a new role, such as "writer," it overrides their old role.

Conversely, if a file inherits role=writer from a folder, and is moved to another folder that provides a "reader" role, the file now inherits role=reader.

Inherited permissions can't be removed from a file or folder in a shared drive. Instead these permissions must be adjusted on the direct or indirect parent from which they were inherited. Inherited permissions can be removed from items under "My Drive" or "Shared with me."

Conversely, inherited permissions can be overridden on a file or folder in My Drive. So, if a file inherits role=writer from a My Drive folder, you can set role=reader on the file to lower its permission level.

Capabilities

The permissions resource doesn't ultimately determine the current user's ability to perform actions on a file or folder. Instead, the files resource contains a collection of boolean capabilities fields used to indicate whether an action can be performed on a file or folder. The Google Drive API sets these fields based on the current user's permissions resource associated with the file or folder.

For example, when Alex logs into your app and tries to share a file, Alex's role is checked for permissions on the file. If the role allows them to share a file, the capabilities related to the file, such as canShare, are filled in relative to the role. If Alex wants to share the file, your app checks the capabilities to ensure canShare is set to true.

For an example of retrieving file capabilities, see Verify user permissions.

Create a permission

The following two fields are necessary when creating a permission:

  • type: The type identifies the scope of the permission (user, group, domain, or anyone). A permission with type=user applies to a specific user whereas a permission with type=domain applies to everyone in a specific domain.

  • role: The role field identifies the operations that the type can perform. For example, a permission with type=user and role=reader grants a specific user read-only access to the file or folder. Or, a permission with type=domain and role=commenter lets everyone in the domain add comments to a file. For a complete list of roles and the operations permitted by each, refer to Roles and permissions.

When you create a permission where type=user or type=group, you must also provide an emailAddress to tie the specific user or group to the permission.

When you create a permission where type=domain, you must also provide a domain to tie a specific domain to the permission.

To create a permission:

  1. Use the create() method with the fileId path parameter for the associated file or folder.
  2. In the request body, specify the type and role.
  3. If type=user or type=group, provide an emailAddress. If type=domain, provide a domain.

Show an example

The following code sample shows how to create a permission. The response returns an instance of a Permission resource, including the assigned permissionId.

Request

POST https://www.googleapis.com/drive/v3/files/FILE_ID/permissions
{
  "requests": [
    {
        "type": "user",
        "role": "commenter",
        "emailAddress": "alex@altostrat.com"
    }
  ]
}

Response

{
    "kind": "drive#permission",
    "id": "PERMISSION_ID",
    "type": "user",
    "role": "commenter"
}

Use target audiences

Target audiences are groups of people—such as departments or teams—that you can recommend for users to share their items with. You can encourage users to share items with a more specific or limited audience rather than your entire organization. Target audiences can help you improve the security and privacy of your data, and make it easier for users to share appropriately. For more information, see About target audiences.

To use target audiences:

  1. In the Google Admin console, go to Menu > Directory > Target audiences.

    Go to Target audiences

    You must be signed in using an account with super administrator privileges for this task.

  2. In the Target audiences list, click the name of the target audience. To create a target audience, see Create a target audience

  3. Copy the unique ID from the target audience URL: https://admin.google.com/ac/targetaudiences/ID.

  4. Create a permission with type=domain, and set the domain field to ID.audience.googledomains.com.

To view how users interact with target audiences, see User experience for link sharing.

Retrieve all permissions for a file, folder, or shared drive

Use the list() method on the permissions resource to retrieve all permissions for a file, folder, or shared drive.

Show an example

The following code sample shows how to get all permissions. The response returns a list of permissions.

Request

GET https://www.googleapis.com/drive/v3/files/FILE_ID/permissions

Response

{
  "kind": "drive#permissionList",
  "permissions": [
    {
      "id": "PERMISSION_ID",
      "type": "user",
      "kind": "drive#permission",
      "role": "commenter"
    }
  ]
}

Verify user permissions

When your app opens a file, it should check the file's capabilities and render the UI to reflect the permissions of the current user. For example, if the user doesn't have a canComment capability on the file, the ability to comment should be disabled in the UI.

For more information about capabilities, see the Capabilities section.

To check the capabilities, call the get() method on the files resource with the fileId path parameter and the fields parameter set to the capabilities field. For further information on returning fields using the fields parameter, see Return specific fields for a file.

Show an example

The following code sample shows how to verify user permissions. The response returns a list of capabilities the user has on the file. Each capability corresponds to a fine-grained action that a user can take. Some fields are only populated for items in shared drives.

Request

GET https://www.googleapis.com/drive/v3/files/FILE_ID?fields=capabilities

Response

{
  "capabilities": {
    "canAcceptOwnership": false,
    "canAddChildren": false,
    "canAddMyDriveParent": false,
    "canChangeCopyRequiresWriterPermission": true,
    "canChangeSecurityUpdateEnabled": false,
    "canComment": true,
    "canCopy": true,
    "canDelete": true,
    "canDownload": true,
    "canEdit": true,
    "canListChildren": false,
    "canModifyContent": true,
    "canModifyContentRestriction": true,
    "canModifyLabels": true,
    "canMoveChildrenWithinDrive": false,
    "canMoveItemOutOfDrive": true,
    "canMoveItemWithinDrive": true,
    "canReadLabels": true,
    "canReadRevisions": true,
    "canRemoveChildren": false,
    "canRemoveMyDriveParent": true,
    "canRename": true,
    "canShare": true,
    "canTrash": true,
    "canUntrash": true
  }
}

Determine the role source for shared drive files and folders

To change the role on a file or folder, you must know the source of the role. For shared drives, the source of a role can be based on membership to the shared drive, the role on a folder, or the role on a file.

To determine the role source for a shared drive, or items within that drive, call the get() method on the permissions resource with the fileId and permissionId path parameters, and the fields parameter set to the permissionDetails field.

To find the permissionId, use the list() method on the permissions resource with the fileId path parameter. To fetch the permissionDetails field on the list request, set the fields parameter to permissions/permissionDetails.

This field enumerates all inherited and direct file permissions for the user, group, or domain.

Show an example

The following code sample shows how to determine the role source. The response returns the permissionDetails of a permissions resource. The inheritedFrom field provides the ID of the item from which the permission is inherited.

Request

GET https://www.googleapis.com/drive/v3/files/FILE_ID/permissions/PERMISSION_ID?fields=permissionDetails&supportsAllDrives=true

Response

{
  "permissionDetails": [
    {
      "permissionType": "member",
      "role": "commenter",
      "inheritedFrom": "INHERITED_FROM_ID",
      "inherited": true
    },
    {
      "permissionType": "file",
      "role": "writer",
      "inherited": false
    }
  ]
}

Change permissions

To change permissions on a file or folder, you can change the assigned role:

  1. Call the update() method on the permissions resource with the permissionId path parameter set to the permission to change and the fileId path parameter set to the associated file, folder, or shared drive. To find the permissionId, use the list() method on the permissions resource with the fileId path parameter.

  2. In the request, identify the new role.

You can grant permissions on individual files or folders in a shared drive even if the user or group is already a member. For example, Alex has role=commenter as part of their membership to a shared drive. However, your app can grant Alex role=writer for a file in a shared drive. In this case, because the new role is more permissive than the role granted through their membership, the new permission becomes the effective role for the file or folder.

Show an example

The following code sample shows how to change permissions on a file or folder from commenter to writer. The response returns an instance of a permissions resource.

Request

PATCH https://www.googleapis.com/drive/v3/files/FILE_ID/permissions/PERMISSION_ID
{
  "requests": [
    {
        "role": "writer"
    }
  ]
}

Response

{
  "kind": "drive#permission",
  "id": "PERMISSION_ID",
  "type": "user",
  "role": "writer"
}

List and resolve pending access proposals

An access proposal is a proposal from a requester to an approver to grant a recipient access to a Drive item.

An approver can review and act on all unresolved access proposals across Drive files. This means you can speed up the approval process by programmatically querying for access proposals and then resolving them. It also allows proposals to be viewed in aggregate by an approver.

The Drive API provides the accessproposals resource so you can view and resolve pending access proposals. The methods of the accessproposals resource work on files, folders, the files within a shared drive but not on the shared drive.

The following terms are specific to access proposals:

  • Requester: The user initiating the access proposal to a Drive item.
  • Recipient: The user receiving the additional permissions on a file if the access proposal is granted. Many times the recipient is the same as the requester but not always.
  • Approver: The user responsible for approving (or denying) the access proposal. This is typically because they're an owner on the document or they have the ability to share the document.

List pending access proposals

To list all pending access proposals on a Drive item, call the list() method on the accessproposals resource and include the fileId path parameter.

Only approvers on a file can list the pending proposals on a file. An approver is a user with the can_approve_access_proposals capability on the file. If the requester isn't an approver, an empty list is returned. For more information about capabilities, see the Capabilities section.

The response body consists of an AccessProposal object representing a list of unresolved access proposals on the file.

The AccessProposal object includes info about each proposal such as the requester, the recipient, and the message that the requester added. It also includes an AccessProposalRoleAndView object that groups the requester's proposed role with a view. Since role is a repeated field, multiples could exist for each proposal. For example, a proposal might have an AccessProposalRoleAndView object of role=reader and view=published, plus an additional AccessProposalRoleAndView object with only the role=writer value. For more information, see Views.

Pass the following query parameters to customize pagination of, or filter, access proposals:

  • pageToken: A page token, received from a previous list call. Provide this token to retrieve the subsequent page.

  • pageSize: The maximum number of access proposals to return per page.

Resolve pending access proposals

To resolve all pending access proposals on a Drive item, call the resolve() method on the accessproposals resource and include the fileId and proposalId path parameters.

The resolve() method includes an action query parameter that denotes the action to take on the proposal. The Action object tracks the state change of the proposal so we know if it's being accepted or denied.

The resolve() method also includes the optional query parameters of role and view. The only supported roles are writer, commenter, and reader. If the role isn't specified, it defaults to reader. An additional optional query parameter of send_notification lets you send an email notification to the requester when the proposal is accepted or denied.

Just as with the list() method, users resolving the proposal must have the can_approve_access_proposals capability on the file. For more information about capabilities, see the Capabilities section.

Proposals are resolved using the same patterns listed under Scenarios for sharing Drive resources. If there are multiple proposals for the same user, but with different roles, the following applies:

  • If one proposal is accepted and one is denied, the accepted role applies to the Drive item.
  • If both proposals are accepted at the same time, the proposal with the higher permission (for example, role=writer versus role=reader) is applied. The other access proposal is removed from the item.

After sending a proposal to the resolve() method, the sharing action is complete. The AccessProposal is no longer returned through the list() method. Once the proposal is accepted, the user must use the permissions collection to update permissions on a file or folder. For more information, see the Change permissions section.

Revoke access to a file or folder

To revoke access to a file or folder, call the delete() method on the permissions resource with the fileId and the permissionId path parameters set to delete the permission.

For items in "My Drive," it's possible to delete an inherited permission. Deleting an inherited permission revokes access to the item and child items, if any.

For items in a shared drive, inherited permissions cannot be revoked. Update or revoke the permission on the parent file or folder instead.

The delete() method is also used to delete permissions directly applied to a shared drive file or folder.

Show an example

The following code sample shows how to revoke access by deleting a permissionId. If successful, the response body is empty. To confirm the permission is removed, use the list() method on the permissions resource with the fileId path parameter.

Request

DELETE https://www.googleapis.com/drive/v3/files/FILE_ID/permissions/PERMISSION_ID

Transfer file ownership to another Google Workspace account in the same organization

Ownership of files existing in "My Drive" can be transferred from one Google Workspace account to another account in the same organization. An organization that owns a shared drive owns the files within it. Therefore, ownership transfers are not supported for files and folders in shared drives. Organizers of a shared drive can move items from that shared drive and into their own "My Drive" which transfers the ownership to them.

To transfer ownership of a file in "My Drive", do one of the following:

  • Create a file permission granting a specific user (type=user) owner access (role=owner).

  • Update an existing file's permission with role=owner and transfer ownership to the specified user (transferOwnership=true).

Transfer file ownership from one consumer account to another

Ownership of files can be transferred between one consumer account to another. However, Drive doesn't transfer ownership of a file between the two consumer accounts until the prospective owner explicitly consents to the transfer. To transfer file ownership from one consumer account to another:

  1. The current owner initiates an ownership transfer by creating or updating the prospective owner's file permission. The permission must include these settings: role=writer, type=user, and pendingOwner=true. If the current owner is creating a permission for the prospective owner, an email notification is sent to the prospective owner indicating that they're being asked to assume ownership of the file.

  2. The prospective owner accepts the ownership transfer request by creating or updating their file permission. The permission must include these settings: role=owner and transferOwnership=true. If the prospective owner is creating a new permission, an email notification is sent to the previous owner indicating that ownership has been transferred.

When a file is transferred, the previous owner's role is downgraded to writer.

Change multiple permissions with batch requests

We strongly recommend using batch requests to modify multiple permissions.

The following is an example of performing a batch permission modification with a client library.

Java

drive/snippets/drive_v3/src/main/java/ShareFile.java
import com.google.api.client.googleapis.batch.BatchRequest;
import com.google.api.client.googleapis.batch.json.JsonBatchCallback;
import com.google.api.client.googleapis.json.GoogleJsonError;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.Permission;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/* Class to demonstrate use-case of modify permissions. */
public class ShareFile {

  /**
   * Batch permission modification.
   * realFileId file Id.
   * realUser User Id.
   * realDomain Domain of the user ID.
   *
   * @return list of modified permissions if successful, {@code null} otherwise.
   * @throws IOException if service account credentials file not found.
   */
  public static List<String> shareFile(String realFileId, String realUser, String realDomain)
      throws IOException {
        /* Load pre-authorized user credentials from the environment.
         TODO(developer) - See https://developers.google.com/identity for
         guides on implementing OAuth2 for your application.application*/
    GoogleCredentials credentials = GoogleCredentials.getApplicationDefault()
        .createScoped(Arrays.asList(DriveScopes.DRIVE_FILE));
    HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(
        credentials);

    // Build a new authorized API client service.
    Drive service = new Drive.Builder(new NetHttpTransport(),
        GsonFactory.getDefaultInstance(),
        requestInitializer)
        .setApplicationName("Drive samples")
        .build();

    final List<String> ids = new ArrayList<String>();


    JsonBatchCallback<Permission> callback = new JsonBatchCallback<Permission>() {
      @Override
      public void onFailure(GoogleJsonError e,
                            HttpHeaders responseHeaders)
          throws IOException {
        // Handle error
        System.err.println(e.getMessage());
      }

      @Override
      public void onSuccess(Permission permission,
                            HttpHeaders responseHeaders)
          throws IOException {
        System.out.println("Permission ID: " + permission.getId());

        ids.add(permission.getId());

      }
    };
    BatchRequest batch = service.batch();
    Permission userPermission = new Permission()
        .setType("user")
        .setRole("writer");

    userPermission.setEmailAddress(realUser);
    try {
      service.permissions().create(realFileId, userPermission)
          .setFields("id")
          .queue(batch, callback);

      Permission domainPermission = new Permission()
          .setType("domain")
          .setRole("reader");

      domainPermission.setDomain(realDomain);

      service.permissions().create(realFileId, domainPermission)
          .setFields("id")
          .queue(batch, callback);

      batch.execute();

      return ids;
    } catch (GoogleJsonResponseException e) {
      // TODO(developer) - handle error appropriately
      System.err.println("Unable to modify permission: " + e.getDetails());
      throw e;
    }
  }
}

Python

drive/snippets/drive-v3/file_snippet/share_file.py
import google.auth
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError


def share_file(real_file_id, real_user, real_domain):
  """Batch permission modification.
  Args:
      real_file_id: file Id
      real_user: User ID
      real_domain: Domain of the user ID
  Prints modified permissions

  Load pre-authorized user credentials from the environment.
  TODO(developer) - See https://developers.google.com/identity
  for guides on implementing OAuth2 for the application.
  """
  creds, _ = google.auth.default()

  try:
    # create drive api client
    service = build("drive", "v3", credentials=creds)
    ids = []
    file_id = real_file_id

    def callback(request_id, response, exception):
      if exception:
        # Handle error
        print(exception)
      else:
        print(f"Request_Id: {request_id}")
        print(f'Permission Id: {response.get("id")}')
        ids.append(response.get("id"))

    # pylint: disable=maybe-no-member
    batch = service.new_batch_http_request(callback=callback)
    user_permission = {
        "type": "user",
        "role": "writer",
        "emailAddress": "user@example.com",
    }
    batch.add(
        service.permissions().create(
            fileId=file_id,
            body=user_permission,
            fields="id",
        )
    )
    domain_permission = {
        "type": "domain",
        "role": "reader",
        "domain": "example.com",
    }
    domain_permission["domain"] = real_domain
    batch.add(
        service.permissions().create(
            fileId=file_id,
            body=domain_permission,
            fields="id",
        )
    )
    batch.execute()

  except HttpError as error:
    print(f"An error occurred: {error}")
    ids = None

  return ids


if __name__ == "__main__":
  share_file(
      real_file_id="1dUiRSoAQKkM3a4nTPeNQWgiuau1KdQ_l",
      real_user="gduser1@workspacesamples.dev",
      real_domain="workspacesamples.dev",
  )

Node.js

drive/snippets/drive_v3/file_snippets/share_file.js
/**
 * Batch permission modification
 * @param{string} fileId file ID
 * @param{string} targetUserEmail username
 * @param{string} targetDomainName domain
 * @return{list} permission id
 * */
async function shareFile(fileId, targetUserEmail, targetDomainName) {
  const {GoogleAuth} = require('google-auth-library');
  const {google} = require('googleapis');

  // Get credentials and build service
  // TODO (developer) - Use appropriate auth mechanism for your app
  const auth = new GoogleAuth({
    scopes: 'https://www.googleapis.com/auth/drive',
  });
  const service = google.drive({version: 'v3', auth});
  const permissionIds = [];

  const permissions = [
    {
      type: 'user',
      role: 'writer',
      emailAddress: targetUserEmail, // 'user@partner.com',
    },
    {
      type: 'domain',
      role: 'writer',
      domain: targetDomainName, // 'example.com',
    },
  ];
  // Note: Client library does not currently support HTTP batch
  // requests. When possible, use batched requests when inserting
  // multiple permissions on the same item. For this sample,
  // permissions are inserted serially.
  for (const permission of permissions) {
    try {
      const result = await service.permissions.create({
        resource: permission,
        fileId: fileId,
        fields: 'id',
      });
      permissionIds.push(result.data.id);
      console.log(`Inserted permission id: ${result.data.id}`);
    } catch (err) {
      // TODO(developer): Handle failed permissions
      console.error(err);
    }
  }
  return permissionIds;
}

PHP

drive/snippets/drive_v3/src/DriveShareFile.php
use Google\Client;
use Google\Service\Drive;
function shareFile()
{
    try {
        $client = new Client();
        $client->useApplicationDefaultCredentials();
        $client->addScope(Drive::DRIVE);
        $driveService = new Drive($client);
        $realFileId = readline("Enter File Id: ");
        $realUser = readline("Enter user email address: ");
        $realDomain = readline("Enter domain name: ");
        $ids = array();
            $fileId = '1sTWaJ_j7PkjzaBWtNc3IzovK5hQf21FbOw9yLeeLPNQ';
            $fileId = $realFileId;
            $driveService->getClient()->setUseBatch(true);
            try {
                $batch = $driveService->createBatch();

                $userPermission = new Drive\Permission(array(
                    'type' => 'user',
                    'role' => 'writer',
                    'emailAddress' => 'user@example.com'
                ));
                $userPermission['emailAddress'] = $realUser;
                $request = $driveService->permissions->create(
                    $fileId, $userPermission, array('fields' => 'id'));
                $batch->add($request, 'user');
                $domainPermission = new Drive\Permission(array(
                    'type' => 'domain',
                    'role' => 'reader',
                    'domain' => 'example.com'
                ));
                $userPermission['domain'] = $realDomain;
                $request = $driveService->permissions->create(
                    $fileId, $domainPermission, array('fields' => 'id'));
                $batch->add($request, 'domain');
                $results = $batch->execute();

                foreach ($results as $result) {
                    if ($result instanceof Google_Service_Exception) {
                        // Handle error
                        printf($result);
                    } else {
                        printf("Permission ID: %s\n", $result->id);
                        array_push($ids, $result->id);
                    }
                }
            } finally {
                $driveService->getClient()->setUseBatch(false);
            }
            return $ids;
    } catch(Exception $e) {
        echo "Error Message: ".$e;
    }

}

.NET

drive/snippets/drive_v3/DriveV3Snippets/ShareFile.cs
using Google.Apis.Auth.OAuth2;
using Google.Apis.Drive.v3;
using Google.Apis.Drive.v3.Data;
using Google.Apis.Requests;
using Google.Apis.Services;

namespace DriveV3Snippets
{
    // Class to demonstrate use-case of Drive modify permissions.
    public class ShareFile
    {
        /// <summary>
        /// Batch permission modification.
        /// </summary>
        /// <param name="realFileId">File id.</param>
        /// <param name="realUser">User id.</param>
        /// <param name="realDomain">Domain id.</param>
        /// <returns>list of modified permissions, null otherwise.</returns>
        public static IList<String> DriveShareFile(string realFileId, string realUser, string realDomain)
        {
            try
            {
                /* Load pre-authorized user credentials from the environment.
                 TODO(developer) - See https://developers.google.com/identity for
                 guides on implementing OAuth2 for your application. */
                GoogleCredential credential = GoogleCredential.GetApplicationDefault()
                    .CreateScoped(DriveService.Scope.Drive);

                // Create Drive API service.
                var service = new DriveService(new BaseClientService.Initializer
                {
                    HttpClientInitializer = credential,
                    ApplicationName = "Drive API Snippets"
                });

                var ids = new List<String>();
                var batch = new BatchRequest(service);
                BatchRequest.OnResponse<Permission> callback = delegate(
                    Permission permission,
                    RequestError error,
                    int index,
                    HttpResponseMessage message)
                {
                    if (error != null)
                    {
                        // Handle error
                        Console.WriteLine(error.Message);
                    }
                    else
                    {
                        Console.WriteLine("Permission ID: " + permission.Id);
                    }
                };
                Permission userPermission = new Permission()
                {
                    Type = "user",
                    Role = "writer",
                    EmailAddress = realUser
                };

                var request = service.Permissions.Create(userPermission, realFileId);
                request.Fields = "id";
                batch.Queue(request, callback);

                Permission domainPermission = new Permission()
                {
                    Type = "domain",
                    Role = "reader",
                    Domain = realDomain
                };
                request = service.Permissions.Create(domainPermission, realFileId);
                request.Fields = "id";
                batch.Queue(request, callback);
                var task = batch.ExecuteAsync();
                task.Wait();
                return ids;
            }
            catch (Exception e)
            {
                // TODO(developer) - handle error appropriately
                if (e is AggregateException)
                {
                    Console.WriteLine("Credential Not found");
                }
                else
                {
                    throw;
                }
            }
            return null;
        }
    }
}