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:
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.
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?