“Token Used Too Late” Error with Google Sign-In on Android

…and how I fixed it…

Brian Terczynski
4 min readDec 20, 2022
Photo by Shubham Dhage on Unsplash

I recently had to implement Google Sign-in for an Android app. I followed the instructions for doing so, creating my GoogleSignInOptions object and creating the Intent similar to the following:

val options = GoogleSignInOptions
.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.requestIdToken(<my_service_client_id_token>)
.build()
val client = GoogleSignIn.getClient(activity, options)
googleSignInClient.signOut()
activity.startActivityForResult(client.signInIntent, <my_request_code>)

I called requestIdToken(...) so that I could pull the idToken from the GoogleSignInAccount (returned to my Activity) and send it to my backend for authentication/authorization.

This code worked fine, and I was able to logout and login to my app several times with Google Sign-in. At least, it worked for a little bit. But after about an hour, my backend would return the following error:

Google_Auth_Exception: Token used too late: 1668030701 > 1667984931

This stumped me. Why would a new login session produce a token that was already considered stale?

I looked up some online resources on this error, like this StackOverflow article. That article recommended using an OAuth Refresh Token. However, I could not find any such token anywhere in GoogleSignInAccount. Nor could I find any API calls to get that token. And furthermore, it was not clear to me that our backend API was equipped to accept such tokens.

I then noticed in this documentation that silentSignIn() was supposed to refresh your token for you. I tried it and it also did not work. I really did not know what do at this point.

All my testing (so far) was being done on an emulator. To diagnose the issue further I tried manually setting the clock on my emulator ahead by over an hour. I did that . . . and it worked! The backend accepted my token.

I did some further tests, and also inspected the actual token being generated. And I observed the following:

  • If you are starting with a fresh install of your app, or the internal storage for your app is clear, then a new token is generated.
  • If you call the Google Sign-in code and the clock on the emulator/device is < 1 hour after the initial token was generated, the same token will be reused.
  • However, if more than an hour has passed according to the device clock, then a new token is generated.

So it would appear that the Google Sign-in library only generates a new token if an hour has passed since the prior token was generated†.

But then why was I getting the above error after using my app for over an hour? Surely a new token should have been generated on the device after an hour. Eventually I noticed something odd. If I closed my laptop and then opened it back up after several minutes (or even hours), the clock on my emulator would be wrong. It acted like no time had passed while the computer was asleep. So if I closed my laptop at, say, 10:38am and then opened it back up at, say, 11:50am, the clock on my emulator still said 10:38am!

So the problem was the clock would fall behind on my emulator. And apparently the Google Sign-in code would not bother to generate a new token because it did not think an hour had passed. But of course on the servers it was over an hour later so the server code would complain.

So it turns out all along that my code was working. It was an incorrect/lagging clock on the emulator that was causing the “token used too late” error. The workaround was to update the clock on my emulator.

Could this be a real problem in production? I suppose…if a user decided to turn off automatic clock synchronization and manually set their device clock back. Merely setting the time zone I would guess would not affect things because the timestamp is likely normalized to UNIX epoch time (I am guessing). So in most cases this probably will not be an issue; probably just in certain edge cases. It seems this issue is more likely for emulators when the clock lags after a system sleep.

Note also that this is just what happened to me for my particular system setup. It happened for emulators running in separate windows (not within Android Studio) on a Mac (I saw this both on Intel and Apple Silicon). I even saw this happen once on Ubuntu after restarting a dead emulator after some time had passed. But I cannot say this will happen for all systems/setups.

But the point is, if you see the “token used too late” error, check the clock on your device/emulator.

† Not an authoritative answer; just based on my observation.

--

--

Brian Terczynski

Documenting my learnings on my journey as a software engineer.