Mk-Etlinger
Mk-Etlinger

Reputation: 174

403 errors for Gdrive API V3 when switching between multiple accounts

I'm looking for a solution to help users bypass a 403 forbidden when they switch accounts and click a webViewLink or webContentLink to download a file.

We're using Gdrive API V3(node) with a google service account. We're aggregating files to be easily accessed by our team. The server populates the content and then users access them via a link.

So the issue is this:

This is totally understandable, Google doesn't know that it's the same person trying to access the content.

A few high level solutions I thought of:

  1. When link is clicked, add a permission to allow anyone to view it, and set it to expire within n seconds(might not be possible with permissions.create)
  2. Somehow save the correct auth and use that for when you click a link(realizing that I'm not sure how the browser knows which token to send)
  3. Turn on "Anyone with link can view"(this is problematic for security reasons, in case someone left the company and still had the link or someone stumbled upon it)
  4. Add auth to the client with the service account credentials
  5. Export and download these files on the server directly(possible with .key and other weird formats?)

A lot of the files needing to be accessed are .key and .mov among others such as .ppt and drive files/folders.

So two(ish) questions here:

  1. What's the best way to address this issue? Is it possible to use the nodejs-client library to download all of these filetypes programmatically? Is this something that delegating domain-wide authority might solve?

  2. Is it possible to specify which credentials are used client side, even though the server is doing all of the initial auth?

Thanks for any help and insight here! This is a total pain!

Upvotes: 2

Views: 1035

Answers (1)

Mk-Etlinger
Mk-Etlinger

Reputation: 174

Here's the quick fix solution:

403 error from Google Drive direct link due to multiple accounts logged in

You can use drive.google.com/u/1/uc?id=DOCID or drive.google.com/a/mycorporatedomain.com/uc?id=DOCID

However, do not rely on these URL's not changing in the future.

Here's a more robust solution if you're using a server side API:

The idea is to hijack the link being clicked, get the metadata you need(ID, filename, mimeType) and request the file from google via the Node server. You can specify the response as a stream, and send that stream to be opened via an inline attachment.

These two links will help:

node/express Force browser to download file with custom name

How to send a file from remote URL as a GET response in Node.js Express app?

In the context of an Express App, here's what it might look like:

// I'm using an async function here, but it may not be best practice.
app.get('/download', async function(req, res, next) {
  // get the metadata from req.query
  const fileId = req.query.id;
  const filename = req.query.name;
  const mimeType = req.query.mimeType;
  const inlineFilename = `inline;filename=${ filename }`;

  // Set the Content-Disposition to specify a filename
  // Set the Content-Type to accept a stream, because that's what we want back from google.
  res.set("Content-Disposition", inlineFilename);
  res.set("Content-Type", "application/octet-stream");

  // This returns a data stream from google so that we are able to pipe the result.
  const fileStream = await downloadFile(fileId);

  // Pipe the stream to the res. This sends the file stream to the client to be downloaded
  fileStream.pipe(res);

});

downloadFile can look something like this(using google-api-nodejs-client):

downloadFile: async function(fileId) {
  try {      
    const response = await drive.files.get(
      {fileId, alt: 'media'},
      {responseType: 'stream'}
    );

    return response.data
  } catch (error) {
    console.error(error);
 }

}

Upvotes: 2

Related Questions