googleapis / google-api-nodejs-client

Google's officially supported Node.js client library for accessing Google APIs. Support for authorization and authentication with OAuth 2.0, API Keys and JWT (Service Tokens) is included.
https://googleapis.dev/nodejs/googleapis/latest/
Apache License 2.0
11.38k stars 1.91k forks source link

Cannot set permissions on new folder after being created in drive #3324

Closed razznblue closed 1 year ago

razznblue commented 1 year ago

Hello! After creating a new folder in the drive, I am trying to give my regular gmail account permissions so I can see the folder in the drive.

I have tried setting the permission of the folder after its creation. And I have tried researching for solutions on stack overflow but none of them worked for my case so here I am 😄


//Auth config and Scopes
const SCOPES = ['https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/drive.file'];
const auth = new google.auth.GoogleAuth({
    keyFile: CREDS_PATH,
    scopes: SCOPES
});

export const addNewFolder = async (folderName, category) => {

  const driveService = google.drive({ version: 'v3', auth });
  const parentFolderId = [getId(category)];

  const file = await createFolder(folderName, parentFolderId, driveService);
  console.log(file.data.id);
  // At this point, the folder has been created and the id is logged.

  // This code does not work and throws a 403.
  const folderId = file.data.id;
  if (!folderId) return;
  const res2 = await driveService.permissions
    .create({
      resource: {
        type: "user",
        role: "owner",
        emailAddress: "<EMAIL_ADDRESS_THAT_NEEDS_ACCESS>" 
      },
      fileId: folderId,
      fields: "id",
      transferOwnership: true,
      moveToNewOwnersRoot: true,
    })
    .catch((err) => console.log(err));
}

const createFolder = async (folderName, parentFolderId, service) => {
  const fileMetadata = {
    name: folderName,
    mimeType: 'application/vnd.google-apps.folder',
  };
  try {
    return await service.files.create({
      resource: fileMetadata,
      fields: 'id',
      parents: [parentFolderId]
    });
  } catch(err) {
    console.error(`Error creating folder ${folderName}`)
  }
}

Error Message: GaxiosError: Consent is required to transfer ownership of a file to another user status: 403 statusText: 'Forbidden'

Let me know if I can clarify anything further for you, thanks!

razznblue commented 1 year ago

I was able to find a workaround using the writer role instead of owner and setting transferOwnership to false. As long as I was creating the folder under a folder I already had access to, I am able to view the folder in the drive!

export const addNewFolder = async (folderName, category) => {
  const driveService = google.drive({ version: 'v3', auth });
  const parentFolderId = [matchParentFolderNameToId(category)];

  const file = await createFolder(folderName, parentFolderId, driveService);
  console.log(file.data.id);

  const folderId = file.data.id;
  if (!folderId) return;
  const res2 = await driveService.permissions
    .create({
      resource: {
        type: "user",
        role: "writer", // Change from owner to writer
        emailAddress: "<YOUR_GMAIL_HERE>" 
      },
      fileId: folderId,
      fields: "id",
      transferOwnership: false, // No need to transfer ownership
      moveToNewOwnersRoot: true,
    })
    .catch((err) => console.log(err));
}

const createFolder = async (folderName, parentFolderId, service) => {
  const fileMetadata = {
    name: folderName,
    mimeType: 'application/vnd.google-apps.folder',
    parents: parentFolderId // Your Regular(non service-account) gmail needs access to this folder
  };
  try {
    return await service.files.create({
      resource: fileMetadata,
      fields: 'id'
    });
  } catch(err) {
    console.error(`Error creating folder ${folderName}`)
  }
}

// How I get the ID of the parent folder. Use your own custom logic.
const matchParentFolderNameToId = (category) => {
  const parentFolderName = category;
  const arr = [process.env.DRIVE_IMAGES.split(','), process.env.DRIVE_AUDIO.split(','), process.env.DRIVE_JSON.split(',')];
  for (const item of arr) {
    if (parentFolderName.toUpperCase() === item[0]) {
      console.log(`Found match ${item[0]} - ${item[1]}`);
      return item[1];
    }
  }
}