Android app is reporting as logged in when authentication fails, and Failed token exchange

Hi!

I have multiple tenants in production for different regions. We’ve noticed Android in the UK has started failing for some users. The credential token fails to authenticate when we verify it on our BackEnd.

I’m also seeing some odd errors in the log, that, I believe, are related.

```
{
“date”: “2026-05-19T04:26:33.389Z”,
“type”: “fertft”,
“description”: “Token could not be decoded or is missing in DB”,
“connection_id”: “”,
“client_id”: “”,
“client_name”: “”,
“ip”: “”,
“client_ip”: “”,
“user_agent”: “okhttp 4.12.0 / Other 0.0.0”,
“details”: {
“policy_used”: null
},
“hostname”: “”,
“user_id”: “”,
“user_name”: “”,
“audience”: null,
“scope”: null,
“auth0_client”: {
“name”: “Auth0.Android”,
“env”: {
“android”: “30”
},
“version”: “3.8.0”
},
“location_info”: {
“latitude”: ,
“longitude”: ,
“country_code”: “”,
“country_name”: “”,
“city_name”: “”,
“subdivision_code”: “”,
“subdivision_name”: “”,
“continent_code”: “NA”,
“time_zone”: “America/New_York”,
“country_code3”: “USA”
},
“$event_schema”: {
“version”: “1.0.0”
},
“environment_name”: “prod-uk-1”,
“log_id”: “90020260519042633438927000000000000001223372042014800925”,
“tenant_name”: “”,
“_id”: “90020260519042633438927000000000000001223372042014800925”,
“isMobile”: false,
“id”: “90020260519042633438927000000000000001223372042014800925”
}
```
I’m unsure where to troubelshoot.

I’ve seen past solutions around making sure the application is marked as native, and it is.

this also seems to be limted to android. (Given that it’s only ever using the okhttp library, which is the kotlin/android networking library.)

Hi @techadmin2

Welcome back to the Auth0 Community!

The fertft error code stands for Failed Exchange of Refresh Token for Access Token . The specific description "Token could not be decoded or is missing in DB" almost always indicates that Auth0’s security mechanisms proactively wiped the user’s Refresh Token family from the database due to a perceived Refresh Token Reuse . On Android, this is most commonly caused by network-level retries occurring on spotty mobile connections.

When you have Refresh Token Rotation enabled, every time the Android app uses a Refresh Token to get a new Access Token, Auth0 issues a new Refresh Token and invalidates the old one.

If Auth0 receives the same Refresh Token twice, it assumes a malicious replay attack is occurring. To protect the user, Auth0 immediately revokes the entire token family. Any subsequent attempts by the app to use that token will result in the exact error you are seeing: the token is “missing in the DB”.

Given this is limited to Android and localized to a specific geographic region, here are the most likely sequence of events:

  1. A user in the UK on a spotty mobile data connection attempts to open the app, triggering a token refresh.
  2. The request successfully reaches your Auth0 UK tenant. Auth0 generates the new tokens, updates the database, and sends the HTTP response back.
  3. The network connection drops before the Android device receives the response. Because the Android networking library often has silent connection retries enabled by default, or the app’s internal logic attempts a retry, it fires the exact same request containing the old Refresh Token.
  4. Auth0 receives the old token, flags it as “Reused,” and immediately deletes the token family from the database.
  5. The next time the app tries to refresh, you get the fertft log.

Because the token family has been completely destroyed on the backend, this state is unrecoverable for the affected session. The token cannot be “fixed.”

To resolve this, you must implement a robust catch-and-recover mechanism in your Android codebase. You must ensure your Android application catches the specific authentication exception and routes the user back to the Universal Login screen. If you are using the CredentialsManager in the Auth0.Android SDK, it should look like this:

credentialsManager.getCredentials(object : Callback<Credentials, CredentialsManagerException> {
    override fun onSuccess(credentials: Credentials) {
    }

    override fun onFailure(error: CredentialsManagerException) {
        if (error.isInvalidRefreshToken) {
            credentialsManager.clearCredentials()
            loginUser() 
        }
    }
})

Ensure you are relying strictly on the thread-safe CredentialsManager.getCredentials() method to fetch your tokens before API calls. Do not manually extract the Refresh Token and attempt to hit the /oauth/token endpoint yourself, as managing the concurrency to prevent race conditions across Android coroutines/threads is highly error-prone.

If you have any other questions, please let me know!

Kind Regards,
Nik