Renaud Cerrato
Renaud Cerrato

Reputation: 1357

Google Identity Authorization (Android) : how to get refresh token?

I'm willing to add some kind of Google Drive synchronization to my (native) android app - no backend involved (everything will happen in the app).

As seen in the Google Identity documentation, I'm using an AuthorizationClient to get an access token through the AuthenticationResult :

List<Scopes> requestedScopes = Arrays.asList(DriveScopes.DRIVE_APPDATA);
AuthorizationRequest authorizationRequest = AuthorizationRequest.builder().setRequestedScopes(requestedScopes).build();
Identity.getAuthorizationClient(this)
        .authorize(authorizationRequest)
        .addOnSuccessListener(
            authorizationResult -> {
              if (authorizationResult.hasResolution()) {
                // Access needs to be granted by the user
                PendingIntent pendingIntent = authorizationResult.getPendingIntent();
                try {
                  startIntentSenderForResult(pendingIntent.getIntentSender(), REQUEST_AUTHORIZE, null, 0, 0, 0, null);
                } catch (IntentSender.SendIntentException e) {
                Log.e(TAG, "Couldn't start Authorization UI: " + e.getLocalizedMessage());
                }
              } else {
                // Access already granted, continue with user action
                saveToDriveAppFolder(authorizationResult);
              }
            })
        .addOnFailureListener(e -> Log.e(TAG, "Failed to authorize", e));
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
  super.onActivityResult(requestCode, resultCode, data);
  if (requestCode == MainActivity.REQUEST_AUTHORIZE) {
    AuthorizationResult authorizationResult = Identity.getAuthorizationClient(this).getAuthorizationResultFromIntent(data);
    saveToDriveAppFolder(authorizationResult);
  }
}

And then, building a Drive instance from it:

Drive.Builder(
                GoogleNetHttpTransport.newTrustedTransport(), GsonFactory.getDefaultInstance(),
                HttpCredentialsAdapter(GoogleCredentials.create(AccessToken(authorizationResult.getAccessToken(), null)))
             ).build()

So far, so good, everything is working fine but since AuthorizationResult doesn't contains any refresh token - how am I supposed to handle the expiration of the access token? The app is supposed to sync in the background without any user interactions, so I'm not going to launch the authorization flow again (unless revoked of course).

I'm aware getServerAuthCode() could be sent to your backend to request a pair of access/refresh tokens for server-side access but I don't need (or even want) to access my user's data server-side.

Am I missing something?

Upvotes: 2

Views: 270

Answers (1)

Ali Naddaf
Ali Naddaf

Reputation: 19084

If you need to obtain a refresh token, you need to do the following:

  • In the AuthorizationRequest, you also need to set requestOfflineAccess(YOUR-SERVER-CLIENT-ID). This results in getting back not only an access token, but also an authorization code (AuthCode).
  • This AuthCode can be exchanged for a new access token and a refresh token. This can be done on your mobile device; it is a relatively simple HTTP request, see this for example.

Note that refresh token is something that needs to be closely safe-guarded. You may want to use PKCE for that reason. Hope that helps.

Upvotes: 1

Related Questions