google-drive-apiauthorizationidentityandroid-credential-manager

How to get user account name after Google Drive authorization?


When switching to a new authentication/authorization scheme, via CredentialManager, I had problems with getting the user account name in order to show this name to the user. I studied all the materials that exist on this topic:

How to authenticate Google Sign In using CredentialManager and authorize to Google Drive API in Android? GoogleSignInClient.silentSignIn equivalent flow in Credential Manager API and Authorization API? What is the replacement for GoogleSignIn.getLastSignedInAccount when migrating to Credential Manager API/ Authorization API?

...and much more.

From these materials and discussions, I concluded that to work with Google Drive it is not necessary to do authentication, it is enough to use the Authorization API in accordance with Google documentation. Following the recommendations from some of the stackoverflow discussions given above, I added, in addition to Drive, all possible scopes.

List<Scope> requestedScopes = List.of(new Scope(DriveScopes.DRIVE_FILE),
            new Scope(Scopes.PROFILE),
            new Scope(Scopes.EMAIL),
            new Scope(Scopes.LEGACY_USERINFO_PROFILE),
            new Scope(Scopes.LEGACY_USERINFO_EMAIL),
            new Scope(Scopes.OPEN_ID));
    AuthorizationRequest authorizationRequest = AuthorizationRequest.builder().setOptOutIncludingGrantedScopes(true).setRequestedScopes(requestedScopes).build();

    Identity.getAuthorizationClient(requireActivity())
            .authorize(authorizationRequest)
            .addOnSuccessListener(
                    authorizationResult -> {
                        if (authorizationResult.hasResolution()) {
                            // Access needs to be granted by the user
                            if(!check_only) {
                                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 {
                                mSavedAccount = null;
                            }
                        } else {
                            mSavedAccount = authorizationResult;
                        }
                    })
            .addOnFailureListener(e -> Log.e(TAG, "Failed to authorize", e));

However, authorizationResult.toGoogleSignInAccount().getDisplayName() still returns null.

I tried to use CredentialManager to get the account, but it always opens some window, and I use background data saving to Google Drive and this is unacceptable! I do not understand why a user who has just selected an account for authorization cannot see the name of this account in the application without the authentication procedure!

I've tried every piece of advice I could find, I've been struggling with this for a month now! I'd really like to ask if anyone has found a solution, please share a piece of working code. Advice like "use such and such API" is unlikely to help, I have a whole collection of them, but none of them worked! Thank you in advance!


Solution

  • Michael, since you're using the Authorization APIs, in general, you should expect to get an access token or auth code (depending on the parameters you specify in your request). If you had included the email, profile and openid scopes in your request (as you seem to have done), the access token that you get back through the authorization step is good enough to call the userinfo end-point https://www.googleapis.com/oauth2/v3/userinfo to get corresponding information about the user. There are posts and articles on how to do the last step (for example this one); it amounts to making a simple GET request to that endpoint where in the header of your request, you include your access token (or you can use many libraries that are out there to do that but frankly, making a simple GET call is easier). You will get a json that you can parse easily. Hope that answers your question.