Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unable to stream API response when token is refreshed #260

Closed
yoavniran opened this issue Aug 20, 2014 · 5 comments
Closed

unable to stream API response when token is refreshed #260

yoavniran opened this issue Aug 20, 2014 · 5 comments
Assignees
Labels
🚨 This issue needs some love. triage me I really want to be triaged.

Comments

@yoavniran
Copy link

Hello, please keep in mind im fairly new to node development so some of my assumptions may be wrong.

Im working on an app that allows downloading files from g-drive offline, as in the server keeps the user's token so it can access their files without needing to login every time.

I want to be able to stream the content of a drive file to the fs so I use a write stream (fs.createWriteStream).
I tried using the oauth2client (https://github.com/google/google-api-nodejs-client/blob/master/lib/auth/oauth2client.js) but that proved impossible for the reason that in all likelihood, the token stored by the app has expired and requires refreshing.

In short, pipe works when the token doesnt require refreshing and doesnt when the token has expired.

In detail, the issue is that if you follow the flow of the oauth2client code (specifically the request method) you see that it checks the expiry date and if passed it will make a request to refresh the token. This request is over HTTP so is asynchronous. At this point, the request method will not be able to return the result from calling "this._makeRequest..." which is actually the return object from calling on the request module (https://github.com/mikeal/request), which is the object needed for calling "pipe()" on.

Unfortunately, this meant I had to write my own client/transporter which is what I did here:
https://gist.github.com/yoavniran/06454e87a3b8d858614e#file-simpleauthtransporter-nodejs
My class relies on emitting events so it can expose the request object even if a token refresh is needed.

I didn't want to write my own code for this but couldnt find a better solution. If there is one Id love to learn and if not I wonder if something like my solution can be integrated into the oauth2client code?

thanks,
Yoav

@rakyll
Copy link
Contributor

rakyll commented Aug 20, 2014

I can confirm that this is a bug, but you don't need to reimplement a client.

Before piping, check if the token is expired and refresh token manually if so. You can set the fresh credentials to create a request object to pipe.

var oauth2client = // ..
var expiryDate = oauth2client.credentials.expiry_date;
// if no expiry time, assume it's not expired
var isTokenExpired = expiryDate ? expiryDate <= (new Date()).getTime() : false;

if (isTokenExpired) {
  oauth2client.refreshAccessToken(function(err) {
    // ... insert/update file.
    drive.files.insert({
      // ...
      auth: oauth2client
    }).pipe(..)
  });
  return;
}

// ... insert/update file.
drive.files.insert({
  // ...
  auth: oauth2client
}).pipe(..)

@yoavniran
Copy link
Author

good point.

Though another reason I implemented my own client was that the oauth client is using the DefaultTransporter which always tries to parse the response body as JSON and in my use-case (downloading a file from g-drive) that is definitely unnecessary and I dont see an easy way to make it stop doing that except for replacing the .transporter with my own transporter or overriding its private "wrapCallback_" method which i dont want to do.

@peili
Copy link

peili commented Sep 7, 2014

I have the same problem. Refreshing token helps before piping...

@ivan
Copy link

ivan commented Jun 1, 2015

I spent some time tracking this down in my program and I'm surprised to see it's already known :-)

Perhaps authClient should be responsible for setting up the .pipe(), so that it's piped into the second request and not the token-refresh request?

Or maybe authClient.request should take a callback that is eventually called with the correct request?

@JustinBeckwith
Copy link
Contributor

Good news! This is no longer an issue. Since switching from request to axios, it now means that the pipe is done on a res.data object that is only returned after a successful refresh. You can see a sample of this in action here:
https://github.com/google/google-api-nodejs-client/blob/master/samples/drive/download.js

Hope this helps!

@yoshi-automation yoshi-automation added triage me I really want to be triaged. 🚨 This issue needs some love. labels Apr 6, 2020
@JustinBeckwith JustinBeckwith self-assigned this Feb 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🚨 This issue needs some love. triage me I really want to be triaged.
Projects
None yet
Development

No branches or pull requests

6 participants