3

This is the comment that led me to ask this question.

I've got a server side Node.js app, using googleapis package. Users log in with their Google accounts, and I store tokens in their session. The credentials I get are as follows

{ access_token: '<AN ACCESS TOKEN>',
  token_type: 'Bearer',
  id_token: '<A LONG ID TOKEN>',
  expiry_date: <A TIMESTAMP> } // why do some places say there's an expires_in instead of this

There's no refresh_token because the users have already logged in for the first time and clicked accept, and I didn't store the refresh token (looks like I should've).

So, when the expiry_date is reached, if the user tries to make a request for us to save something to their google drive, I get an error message:

{ [Error: invalid_request] code: 400 } // ...no further details

My 2-part question:

  • I assume I'm getting that error message because the access_token in my OAuth client object is expired (because the call works fine before the token expires). Is this correct? Why is the error message not more detailed?

  • In the linked answer at the top, the solution is to force the accept prompt again, get the refresh token, and store it permanently, and use it to get a new access token when it expires. Why is this a better option than just checking if the token is expired, and having a user reauthenticate when we want to make a call to the API? Which is the "correct" way to ensure that my logged in users can always make the drive API call to save their documents?

  • it looks like you're using a deprecated endpoint to introspect the token since `expires_in` is indeed the standard behavior that is implemented by Google in more recent endpoints – Hans Z. Sep 07 '16 at 13:10
  • @HansZ. could you clarify the terms "endpoint" and "introspect" here? I'm using the latest version of the google apis client on node.js for this. –  Sep 07 '16 at 20:04

1 Answers1

3
  1. Right, the 400 response is because of the expired access token. I'm not sure why Google doesn't give more detail, but it's common for services to use the 400 status code to indicate some kind of credentials problem. The definition of the status code indicates that it's a client issue.

  2. Both approaches will work and they each have advantages and disadvantages. The client-side re-authentication method you're suggesting has the advantage of making the implementation simpler, since you don't have to store the refresh token and don't have to implement the refresh process. The downside is that forcing the user to re-authenticate every hour is less user-friendly. At the least they will be redirected away from your app, and they may have to explicitly log in or re-authorize as well. You'll just have to look at the trade-offs and pick what works best for your use case.

Community
  • 1
  • 1
Kevin Christopher Henry
  • 46,175
  • 7
  • 116
  • 102
  • My alternative scenario was actually just forcing the user to reauthorize if the access token expired. This would eliminate the need to request "offline" access, which I don't need anyway. To clarify, my goal is to allow even users who have been logged in to my web app for over an hour to save their data to Google Drive (which we do through the API). Having to permanently store each user's refresh token in the database just seems a bit off to me--why should I have to do this? –  Sep 07 '16 at 20:49
  • @GeorgesPompidou: You can certainly ask your users to re-authorize every hour if you want to, but that's rather user-unfriendly. No one wants to be redirected away from the page they're on, and no one enjoys logging in. By contrast, it should be trivial for you to store the refresh token (you're already storing the access token) and that will allow you to update the authorization for a long time without troubling your users. – Kevin Christopher Henry Sep 07 '16 at 22:53
  • The access token is stored in the session which is in an in-memory database and is ephemeral. The refresh token, to my understanding, needs to be stored in the long term database of my application, associated with each user, if I'm only going to prompt the user for permission once. This, coupled with the fact that I need to request "offline access" to get it (which, like I said, my application doesn't need) seems strange to me. That's why I was hoping that there's a better way that I'm missing. –  Sep 08 '16 at 17:26
  • @GeorgesPompidou: OK, I understand you now. I've updated the answer to be more on-point. – Kevin Christopher Henry Sep 08 '16 at 18:08
  • Alright, this is fair. I'm also wondering--does the refresh token ever expire? If it does, will google give me a new one when it does? Or is it just going to sit there in my users table permanently? –  Sep 08 '16 at 18:38
  • @GeorgesPompidou: I'm not sure what Google does, specifically, but according to the specification a new refresh token can be returned along with the new access token when you refresh. If the refresh request ever fails, you just re-authenticate as you were planning to do anyway, and you will get a new refresh token through that process. – Kevin Christopher Henry Sep 08 '16 at 23:45