0

My question: How can I request a OAuth2 credential object to access the Google Drive API, that is automatically refresh after the accessToken is expired?

What I did: I followed the latest suggestions from Google, how to access the Google Drive API on Android by first doing an authentication via Credential Manager and then an authorization via Google Indentiy:

https://developers.google.com/identity/android-credential-manager https://developers.google.com/identity/authorization/android

Also here I found help:

How to authenticate Google Sign In using CredentialManager and authorize to Google Drive API in Android?

My current code for the authentication is the following (for using Credential Manager there are many good code examples easy to find by Google):

    private fun authorizeGoogleDrive() {
        val requestedScopes = listOf(Scope(DriveScopes.DRIVE_READONLY))
        val authorizationRequest = AuthorizationRequest.Builder()
            .setRequestedScopes(requestedScopes)
            .build()
        Identity.getAuthorizationClient(this)
            .authorize(authorizationRequest)
            .addOnSuccessListener { authorizationResult ->
                if (authorizationResult.hasResolution()) {
                    val pendingIntent = authorizationResult.pendingIntent
                    try {
                        val intentSenderRequest = pendingIntent?.let { IntentSenderRequest.Builder(it.intentSender).build() }
                        intentSenderRequest?.let { authorizeGoogleDriveResultReceiver.launch(intentSenderRequest) }
                    } catch (e: IntentSender.SendIntentException) {
                        Log.e(LOG, "SignInActivity/authorizeGoogleDrive Couldn't start Authorization UI: " + e.localizedMessage)
                    }
                } else {
                
                  buildDriveService(authorizationResult)
                  
                }
            }
    }

    private val authorizeGoogleDriveResultReceiver = registerForActivityResult(
        ActivityResultContracts.StartIntentSenderForResult()
    ) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            val authorizationResult: AuthorizationResult = Identity.getAuthorizationClient(
                this
            ).getAuthorizationResultFromIntent(result.data)

            buildDriveService(authorizationResult)

        } else {
            Log.e(LOG, "SignInActivity/authorizeGoogleDriveResultReceiver result.resultCode != Activity.RESULT_OK")
        }
    }
    
    
    fun buildDriveService(authorizationResult: AuthorizationResult) {
        val accessToken = AccessToken(authorizationResult.accessToken, Date(System.currentTimeMillis() + 3600 * 1000))
        val credential = GoogleCredentials.create(accessToken)
        driveService = Drive.Builder(
            GoogleNetHttpTransport.newTrustedTransport(),
            GsonFactory.getDefaultInstance(),
            HttpCredentialsAdapter(credential)
        )
            .setApplicationName(app_name)
            .build()

    }

The access worked well for a while (60 minutes), but then I got the following exception using my driveService Object:

OAuth2Credentials instance does not support refreshing the access token. An instance with a new access token should be used, or a derived type that supports refreshing.

And what is really strange: when I restart my app, I always get the same access token, regardless that I am calling Identity.getAuthorizationClient(this).authorize(authorizationRequest) again.

According to the documentation of com.google.auth.oauth2.GoogleCredentials with extends OAuth2Credentials, refreshing access tokens is not supported.

https://cloud.google.com/java/docs/reference/google-auth-library/latest/com.google.auth.oauth2.OAuth2Credentials

I tried to switch from GoogleCredentials to com.google.auth.oauth2.UserCredentials, hoping that this Class supports automatic token refreshing. But I could not yet successfully use its Builder, always getting a null pointer exception. Also I need a refresh Token calling this Builder:

    val userCredentials = UserCredentials.newBuilder()
        .setClientId(app_name)
        .setAccessToken(accessToken)
        .setRefreshToken(refreshToken)
        .build()

But I don't have a refreshToken. In authorizationResult object I get via Identity.getAuthorizationClient(this).authorize(authorizationRequest), there is only a filed accessToken, but no refreshToken.

What can I do?

0