Google-api-nodejs-client: Refresh a token (Multiple Oauth2Clients)

Created on 22 Feb 2019  路  11Comments  路  Source: googleapis/google-api-nodejs-client

So, i was reading the docs and i saw the only way to refresh a token is this

oauth2client.on('tokens', (tokens) => {
  if (tokens.refresh_token) {
    // store the refresh_token in my database!
    console.log(tokens.refresh_token);
  }
  console.log(tokens.access_token);
});

Isn't it inefficient to add an event to every single client? isn't there a better way to manually check the clients access token and refresh it using the refresh token?

question

Most helpful comment

@richardpeng I agree.

@bcoe The tokens event can't access application context. Where should I put this .on("tokens") in application code?

For example, if use express, the context info is attached in req object, like req.user

I think below way is wrong:

app.post('/post', (req, res) => {
  auth.on('tokens', async (tokens) => {
    const requestingUser = req.user
    const user = await db.findByEmail(requestingUser.email)
    await db.updateGoogleAccountTokensByUser(user)
  })
})

If put auth.on('tokens', (tokens) => {}) on a global environment

auth.on('tokens', (tokens) => {
  // Don't know whose tokens
  const user = ??
  await db.updateGoogleAccountTokensByUser(user)
})

All 11 comments

@supertiger1234
The refresh_token is only provided on the first authorization from the user. Subsequent authorizations, such as the kind you make while testing an OAuth2 integration, will not return the refresh_token again. :)

access_token is good for one hour. If your access_token is close to be expired or expired already the next time you execute, than your token will be refreshed automatically with the use of refresh_token.
By adding an listener on tokens event merely helps you record the new access_token value locally when it is refreshed automatically.

Does that help you?

Ohhh, so it happens automatically?
Also, what if I wanna use the refresh token from a database? Do I just do setCredentials({access_token: db.accessToken})?

Thanks a lot for the quick reply

Hey! I randomly came across this issue and I actually wanted to ask something very similar to @supertiger1234 asked.

What if I want to save the new token to the database? Using the listener becomes very hard in that matter.
What is your suggestion?

Same issue. I want to ask what's the difference about these two ways:

Way 1: oauth2client.setCredentials({access_token: db.accessToken})

Way 2: oauth2client.setCredentials({refresh_token: db.refreshToken})

According to the docs, I think the way 2 is enough. oauth2client will always refresh access token automatically. I don't need worry about the expiration about access token.

oauth2client.on('tokens', (tokens) => {
//store access_token in your database
console.log(tokens.access_token); // for testing
});

this function "oauth2client.on('tokens')" will only run(automatically), when your previous access_token gets expired.
So inside this function, you can get the latest access_token and store it onto your database.
Storing new access_token is important in order to prevent unnecessary requests for a new access token.

@mrdulin @fabiofcferreira for the use-case where credentials are being stored for a long period of time, and you're relying on the refresh_token.

I would recommend storing both the access_token and the refresh_token, and calling oauth2client.setCredentials with both, e.g.,

oauth2client.setCredentials({refresh_token: db.refreshToken, access_token: db.accessToken})

To make sure you have stored the most recent version of the access_token, you will need to use .on("tokens"). There's some useful examples of this pattern in action here. _(sorry this pattern is a bit of a hassle)_.

I hope this helps clarify 馃憤


I'm going to go ahead and close this issue, since I think @supertiger1234 is unblocked, _but_ if other folks have follow up questions, please don't hesitate to open an additional issue.

@bcoe could you update the link to examples of the pattern for storing the access_token and refresh_token. I can't for the life of me figure out how to store my tokens because I don't have access to the user context when using auth.on('tokens', (tokens) => {}). If not something from the user context, what would you use as the key for storing tokens in a database?

@richardpeng I agree.

@bcoe The tokens event can't access application context. Where should I put this .on("tokens") in application code?

For example, if use express, the context info is attached in req object, like req.user

I think below way is wrong:

app.post('/post', (req, res) => {
  auth.on('tokens', async (tokens) => {
    const requestingUser = req.user
    const user = await db.findByEmail(requestingUser.email)
    await db.updateGoogleAccountTokensByUser(user)
  })
})

If put auth.on('tokens', (tokens) => {}) on a global environment

auth.on('tokens', (tokens) => {
  // Don't know whose tokens
  const user = ??
  await db.updateGoogleAccountTokensByUser(user)
})

Like @mrdulin and @richardpeng I would also like to have a solution to manage the tokens refresh for several users (stored in a DB).

Also, what is not clear to me, is what happens if the server is shut down and restarted. I guess the automatic refresh works because google-api-nodejs-client keeps in RAM a list of the tokens to be refreshed. But if this is right, then the RAM is lost whenever the server is restarted.
Then, how to prevent all users to re-authenticate again upon every server upgrade?

Can anyone tell me when am I supposed to call this .on('tokens') event? Is it the first time the user authenticates? Because as far as I understand, if this event is called in subsequent API call, it won't return the refresh_token. And I've discovered that in subsequent API call, I only need to attach the refresh token:

oAuth2Client.setCredentials({
  refresh_token: REFRESH_TOKEN
})

to get a successful response. The Google API client automatically gets the new access token for me.

@richardpeng @mrdulin have u guys found a solution for your problems. I am currently having the same issue with storing access token using token event since cant get any user data inside of event handler

Was this page helpful?
0 / 5 - 0 ratings

Related issues

JustinBeckwith picture JustinBeckwith  路  3Comments

ashishbajaj99 picture ashishbajaj99  路  3Comments

ovaris picture ovaris  路  3Comments

joseparoli picture joseparoli  路  3Comments

nanu-c picture nanu-c  路  3Comments