4

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?

asked Jan 9, 2025 at 11:08
3
  • Hi, may I know, how long you need to test, till authorizationResult.hasResolution() will return true for the 2nd time, after access granted by user? Previously, we are using GoogleSignInClient.silentSignIn to prevent the access token from being expired. But, I am not sure this time - stackoverflow.com/questions/79259001/… Commented Jan 17, 2025 at 2:00
  • I didn't tested much but it's been 8 days so far and it didn't returned true yet. I haven't called any API yet with that token since I switched to some other tasks in the meantime - but my wild guess is that calling authorize is renewing the token if needed. Commented Jan 17, 2025 at 6:23
  • I guess so, because there is no longer silent sign in API. The culprit is, some users have outdated Google Play services. This will cause the new API broken. Commented Jan 17, 2025 at 6:34

1 Answer 1

3
+500

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.

answered Jan 18, 2025 at 0:30
Sign up to request clarification or add additional context in comments.

8 Comments

Custom URI schemes are no longer supported on Chrome apps and are disabled by default on Android as per the documentation. Loopback interface is deprecated for mobile apps and they're recommending to use the Google Sign-in SDK instead (but doesn't mentions use cases for authorization). Redirect URI have to be registered first in the Google Cloud console, so it seems that can't be use outside of backend.
Previously, by using GoogleSignInClient.silentSignIn, user just need to UI login prompt to login once, and will never be prompted again. Does Identity.getAuthorizationClient has the same behavior, without using requestOfflineAccess? Currently, after few days testing without requestOfflineAccess, the user will only be UI login prompted once, and never prompt again. But, I am not sure what will happen after few months, ... Will the user be UI login prompted again after a few months?
I'm not requesting offline access, and I've logged the access token returned every 24h by calling authorize : the access token changes so it seems to be refreshed, no UI prompt. Calling authorize many times consecutively returns the same token though, so the refresh is handled by the system, caching the last token until expiry. Would be nice someone from the Google Identity team confirm.
After a user has given you the grants, then calling the "authorize" method returns an access token to you immediately, without prompting the user (until the user revokes the grants/access). However, Access Token is cached on the device so it is possible that you may get an access token back that is already expired; the cache on the device gets cleaned up but there is always a chance for that to happen. When the local cache is expunged, calling that method returns a new Access Token.
There won't be any UI since user has already given the consent (unless the user goes and revokes that, or the developer does that). The only case that we would need to show the consent again (even if authorize() is called immediately) is if the developer has asked for an offline auth code while setting forceCodeForRefreshToken=true. In your case that you're simply asking for an Access Token, you shouldn't see any subsequent UI.
|

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.