Store and retrieve Google Refresh token

Problem:
I’m having difficulty storing and retrieving users’ Google refresh tokens, which I should theoretically only get the first time the user logs in.

Context:
Setup: SPA with a React front-end and a Node/Express backend.
Signup flow: social login-only with Google

When signing up, we get permissions to query their Google calendar and therefore need their Google refresh token in order to be able to continue to query their Google account without needing them to re-login every hour.

I implemented the flow shown HERE

Questions

  • How do we get Auth0 to hold onto the Google refresh token?
    In auth-lock, I needed to pass scope: offline_access when authorizing the user’s signup in order for Auth0 to not throw away the refresh token. In auth0-spa I don’t see an obvious place to add this scope. I think the most promising options are in the auth_config.json file or in the loginwithredirect() function, but I tried stuff in both and couldn’t get the Google refresh token to show in the profile. How do I get Auth0 to hold onto the Google refresh token?

  • Once Auth0 receives the Google refresh token, how do we retrieve it?
    In auth-lock, I needed to hit the Auth0 Management API to retrieve the user’s profile and include params to get their identities data, which contained the Google refresh token. I’m still able to retrieve identities using this approach now; is this still the right way to do it?

  • Once the Google refresh token is retrieved, how should it be stored long-term?
    It seems like it should be stored in some kind of rule, or in our DB. Auth0 documentation seems to imply that we should store it in DB, which is ironic since one of the main reasons why we used Auth0 is so that we aren’t storing sensitive data. What is the preferred way to store the Google refresh token?

When you use Auth0 and Google social login, you use Auth0 as a broker, which federates to Google as IdP. But your client application (SPA) never gets in touch with Google access or refresh tokens directly, that’s all handled by the Auth0 platform, while your client application only deals with Auth0 tokens.

And specifically for a SPA / auth0-spa-js: there is only an access token involved and no refresh token.

Where/if to store the access token persistently depends on your setup, whether your SPA has a backend or not, and whether you want to keep it stateless or not. See Token Storage

As long as the user has an active Auth0 session, your SPA can always retrieve a new access token via getTokenSilently() (https://auth0.github.io/auth0-spa-js/classes/auth0client.html#gettokensilently) without user interaction. There is no Auth0 refresh token needed here. (And how Auth0 as a broker deals with Google refresh tokens shouldn’t be the concern of your SPA app, because your app only talks to Auth0/the broker.)

So, you or your SPA client application never deals with the Google refresh token nor access token directly.

Update: my above reply only applies for the scenario where you use Google for login/authentication. I missed the initial part of the question that you want to also call the Google calendar API. In this case you would need to deal with the Google tokens directly of course.

Thanks for the detail! Let me see if I am understanding this correctly:

  • With auth0-spa-ja I will never store a Google refresh token
  • Given that I want to get tokens via my backend, whenever I need to query the user’s Google calendar (and need to get a new access_token) I will first get their Auth0 access_token (using getTokenSilently()), then hit the Management API with that access_token to get their IdP’s Access Token (described in this flow)
  • Once I have a user’s IdP’s Access Token, I can use that to make a call to Google to get data. Presumably it still expires in the normal amount of time as any other Google access_token (60 minutes), after which I’d get a status code for a failed request and need to ask the Management API for a new token?
  • I never need to “refresh” the Google access_token since Auth0 essentially does it for me in the background whenever I ask the Management API for a new token?

I totally missed the part in your initial question that you want to call the Google Calendar API later on, not only authenticate the with Google. Will get back to you on this tomorrow, as I’m already out and on mobile.

1 Like

Please ignore my previous answer, as it only applies when you want to login with Google, but in your case you need to also call the Google APIs (such as calendar). Then of course, you’d need to deal with the Google tokens directly. So, sorry about the confusion here.

So according to the docs, for Google, you would need to add access_type: offline to the /authorize request:

Call an Identity Provider API :

For certain Identity Providers, Auth0 will store a Refresh Token which you can use to obtain a new Access Token for the IdP. This works for: BitBucket, Google (OAuth 2.0), […].

Identity Provider Access Tokens :

There is no standard way to renew IdP Access Tokens through Auth0. The mechanism for renewing IdP Access Tokens varies for each provider.

  • Google OAuth 2.0 (you need to pass the parameter access_type=offline when calling the Auth0 /authorize endpoint)

Get the IdP Refresh Tokens in the same way as Access Tokens, using the /api/v2/user/{user-id} endpoint. The Refresh Tokens will be available in the identities array, under the element for the particular connection.

So, regarding our questions:

How do we get Auth0 to hold onto the Google refresh token?

In order to make Auth0 get a refresh token in the first place, your SPA needs to make the authorize request with the parameters:

access_type: "offline"

as well as the respective audience to the authorize request, such as:

connection_scope: "https://www.googleapis.com/auth/calendar.events.readonly"

Example here: Can't get google refresh token using auth0.js - #2 by vinicius.spagnol

Once Auth0 receives the Google refresh token, how do we retrieve it?

Afterwards, the refresh token is in the user profile’s identities, which you can get via Auth0 Management API from your backend.

Once the Google refresh token is retrieved, how should it be stored long-term?

Either store it securely in your backend (i.e. database) or fetch it from a user profile via Auth0 management API when you need it.

Regarding storing the Google tokens, I actually found a similar question here:

1 Like

Using the flow I mentioned above, I no longer call the authorize endpoint. Authentication happens HERE using a React hook.

Are you suggesting that I now need to hit the Auth0 authorize endpoint? I would’ve thought that a feature of using the React hook would’ve been so I wouldn’t be hitting the authorize endpiont in this manner?

If I am required to make a call to the authorize endpoint, how do I do so using React hooks? I don’t see any place where it makes sense to send a request to the authorize endpoint.

@tbhiraki: Sorry for the confusion: in the auth0-spa-js, the /authorize endpoint is called under the hood by the SDK, such as loginWithPopup() or getTokenSilently().

I meant to say that the respective mentioned parameters would need to be added in these wrapper methods. So it would look something like this:

loginWithRedirect({
    access_type: 'offline', 
    connection_scope: 'https://www.googleapis.com/auth/calendar.events.readonly', 
    approval_prompt: 'force'
})

I tested it with the React Quickstart you linked and it works.

1 Like

I would like to know how I use the access_type parameter on auth0-react SDK?

2 Likes

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.