Background
Inside the app, there is a Google-login step to register with the server using a token. This is done via the dependency of :
api('com.google.android.gms:play-services-auth:20.0.0')
The app triggers showing up to 2 dialogs for the user :
- Login (not shown if user has logged in for the currently installed app) :
- Granting permissions (not shown if granted the permissions in the past):
This works fine for most cases.
If the user has already logged in and granted permissions, we can use the token that we got last time, assuming it's not expired. I check if it's expired using:
GoogleSignIn.getLastSignedInAccount(context)?.isExpired`) .
The problem
I've found a special problematic scenario:
- User has logged-in in the past and granted some permissions
- User went to Google-account-manager and revoked the access to the app (here).
- User tried to login again (for example after removal of the app)
On this case, I get a bad token that can't be used. It's actually the exact same token that I got from before revoking the access. It's probably using a cached token from last time, to avoid un-needed communication with Google server.
In this case, the server (of the SDK I work on) will send me an error that this token is invalid (which is correct), as it tries to use it.
This is problematic and seems to me like a bug on Google's SDK (I've reported here), because the token is supposed to work, as the user has re-logged in using the login-dialog, as everything was reset.
What I've tried
I tried to use various API functions, but none of them seem to tell me if the token is valid, or let me request a new token for login dialog in case the current one is invalid.
The only workaround for this that I've found, is that after a single login-dialog, and detecting that there is an error with the token (got it via the server), I choose to logout and re-login entirely:
@WorkerThread
fun logout(context: Context, googleClientId: String) {
val options =
GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestServerAuthCode(googleClientId)
.requestEmail()
.build()
val signInClient = GoogleSignIn.getClient(context, options)
val lastSignedInAccount = GoogleSignIn.getLastSignedInAccount(context)
if (lastSignedInAccount != null) {
Tasks.await(signInClient.revokeAccess())
Tasks.await(signInClient.signOut())
}
}
Only after that, I can login using an Intent that I prepare:
@WorkerThread
fun prepareIntent(context: Context, googleClientId: String): Intent {
val options =
GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestServerAuthCode(googleClientId)
.requestEmail()
.build()
val signInClient = GoogleSignIn.getClient(context, options)
val lastSignedInAccount = GoogleSignIn.getLastSignedInAccount(context)
if (lastSignedInAccount?.isExpired == true) {
var success = false
kotlin.runCatching {
val result: GoogleSignInAccount? = Tasks.await(signInClient.silentSignIn())
success = result?.isExpired == false
}
if (!success)
kotlin.runCatching {
Tasks.await(signInClient.revokeAccess())
Tasks.await(signInClient.signOut())
}
}
return signInClient.signInIntent
}
This isn't a nice thing to do, because the user sees 3 dialogs instead of up to just 2 dialogs as I've shown in the beginning :
- Login
- Grant permissions
- Login again, as the token was invalid.
The questions
How can I avoid 2 login-dialogs ?
Is there an API that forces getting a new token for login dialog?
Is this a known bug, and this is the only workaround I can indeed use?

