node.jsreactjsoauth-2.0google-drive-apigoogle-picker

Google picker on frontend (user login in reactJS) and google drive download on backend (node.js), API v3


I am building a file uploader which provides the user an option to upload files from his google drive. Google picker is set up and working on the frontend (reactJS) and I have the fileID and OAuth token given by Google Picker. I send these to the backend (node.js) and have the Google Drive API over there. I followed the documentation https://developers.google.com/drive/api/v3/manage-downloads and put the oauth token in the auth param in drive.files.get, now I got the following error

Error  GaxiosError: [object Object]
    at Gaxios._request (/home/.../node_modules/gaxios/src/gaxios.ts:112:15)
    at processTicksAndRejections (internal/process/task_queues.js:97:5) {
  response: {
    config: {
      url: 'https://www.googleapis.com/drive/v3/files/1GqxjzMjrDdJquOPeMrFGIMngE20vTrjU?alt=media&key=ya29.6q33c6T418VuSILwq...cLKnBMKEG4vhui8K',
      method: 'GET',
      responseType: 'stream',
      userAgentDirectives: [Array],
      paramsSerializer: [Function],
      headers: [Object],
      params: [Object],
      validateStatus: [Function],
      retry: true,
      retryConfig: [Object]
    },
    data: PassThrough {
      _readableState: [ReadableState],
      readable: true,
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      _writableState: [WritableState],
      writable: false,
      allowHalfOpen: true,
      _transformState: [Object],
      [Symbol(kCapture)]: false
    },
    headers: {
      'alt-svc': 'h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"',
      'cache-control': 'private, max-age=0',
      connection: 'close',
      'content-length': '176',
      'content-type': 'application/json; charset=UTF-8',
      date: 'Wed, 16 Dec 2020 11:42:15 GMT',
      expires: 'Wed, 16 Dec 2020 11:42:15 GMT',
      server: 'UploadServer',
      vary: 'Origin, X-Origin',
      'x-guploader-uploadid': 'ABg5-Uw8z7O1Hpe1od4_dQF9So652TfYS0Mc1vpIu3t4DDXPzB7YvNwQAeHKCvoNBF-7m_pW9e8EHPOgrEHS84HWR7M'
    },
    status: 400,
    statusText: 'Bad Request',
    request: {
      responseURL: 'https://www.googleapis.com/drive/v3/files/1GqxjzMjrDdJquOPeMrFGIMngE20vTrjU?alt=media&key=ya29.6q33c6T418VuSILwq...cLKnBMKEG4vhui8K'
    }
  },
  config: {
    url: 'https://www.googleapis.com/drive/v3/files/1GqxjzMjrDdJquOPeMrFGIMngE20vTrjU?alt=media&key=ya29.6q33c6T418VuSILwq...cLKnBMKEG4vhui8K',
    method: 'GET',
    responseType: 'stream',
    userAgentDirectives: [ [Object] ],
    paramsSerializer: [Function],
    headers: {
      'x-goog-api-client': 'gdcl/4.4.3 gl-node/12.19.0 auth/6.1.3',
      'Accept-Encoding': 'gzip',
      'User-Agent': 'google-api-nodejs-client/4.4.3 (gzip)'
    },
    params: {
      alt: 'media',
      key: 'ya29.6q33c6T418VuSILwq...cLKnBMKEG4vhui8K'
    },
    validateStatus: [Function],
    retry: true,
    retryConfig: {
      currentRetryAttempt: 0,
      retry: 3,
      httpMethodsToRetry: [Array],
      noResponseRetries: 2,
      statusCodesToRetry: [Array]
    }
  },
  code: '400'
}

Here I observed that, there's a "key" parameter but from what I understand there should be an Authorization token. I tried using the file url from POSTMAN using a GET call with Authorization Bearer but it responded with a sign in page.

Questions:

  1. Since I provided a token, shouldn't it download the file directly?
  2. Why isn't the file downloading on the backend?

Note: I did follow the google drive api documentation on node.js but even that prompts user sign in which shouldn't be the case.

Edit: Added the client code as well

Client side (reactjs)

                <GooglePicker
                    clientId={"7...b.apps.googleusercontent.com"}
                    developerKey={"AIz...PY"}
                    scope={["https://www.googleapis.com/auth/drive.readonly"]}
                    onChange={handleFileChange}
                    onAuthenticate={(token) => setDownloadToken(token)}
                    onAuthFailed={(data) => console.log("on auth failed:", data)}
                    multiselect={false}
                    navHidden={false}
                    authImmediate={false}
                    query={"a query string like .txt or fileName"}
                    viewId={"PDFS"}
                >
                    <Button variant="contained" size="small">
                        G-Drive
                    </Button>
                </GooglePicker>{" "}

Node.js Code

export const googleDriveUpload = async (_, {fileID, authToken}) => {
  console.log(fileID, authToken);
  const drive = google.drive({version: 'v3', auth:authToken});

  var dest = fs.createWriteStream('/tmp/resume.pdf');

  drive.files.get({fileId: fileID, alt: 'media'}, 
  {responseType: 'stream'}, (err,  res ) => {
    if (err) {
      console.log("Error " ,err);
    } else {
        res.data.pipe(file);
        console.log("Download complete");
    }
  });

Solution