Skip to content

Invalid refresh token after fresh install #875

@NutMegCode

Description

@NutMegCode

Checklist

Description

I am encountering an “invalid_grant Unknown or invalid refresh token” error when calling .awaitCredentials() once a token has expired after a valid login on a fresh install of my app.

The expected behavior is that when .awaitCredentials() is called after the token has expired the auth0 SDK will implicitly handle token refresh successfully.

Reproduction

The steps I follow to reproduce this error are as follows:

  1. I uninstall my app
  2. I reinstall my app
  3. The webAuthProvider.logIn() is called
  4. I enter my credentials and am successfully authenticated
  5. The success can be seen on the auth0 dashboard logs
  6. In the .onSuccess() of the webAuthProvider.logIn() I use my getCredentialsManager() helper function
  7. The getCredentialsManager() helper function creates a CredentialsManager the first time it is called (subsequent calls will return this credentials manager not create a new one)
  8. I call the .saveCredentials() of the newly created CredentialsManager
  9. I call .awaitCredentials() and print the result to my logCat and see that there is a token, refresh token, and expiresAt
  10. As the app is used every api call uses .awaitCredentials() to retrieve the token that will be passed up in the api header
  11. After the expiresAt time I trigger another api call
  12. .awaitCredentials() is called and fails with an invalid_grant Unknown or invalid refresh token CredentialsManagerException
  13. There is no corresponding error in the Auth0 dashboard

Additional context

After a valid log in I print to logCat the token, refresh token, and expires at properties and they all seem valid. Checking .hasValidCredentials() returns true and until the token expires awaitCredentials() works as expected and is able to retrieve the locally stored credentials successfully so I believe the refresh token is being received and stored correctly.

This error is only encountered on a fresh install, it will persist through valid logins until the app has been closed and re opened, at which point the refresh process will proceed as expected.

There are no corresponding errors on the Auth0 dashboard logs when this invalid_grant is encountered and there is no auth api call for a refresh so I believe the refresh token is being found invalid locally by the auth0 SDK.

I use a companion object to ensure my credentials manager is only initialised once.
I pass "openid profile email offline_access" to the scope of the WebAuthProvider.login()
My Auth0 dashboard settings allow refresh token rotation with a rotation overlap period of 30 seconds. I use the same time frame as the minTTL property passed to awaitCredentials()

I am using Kotlin with Composables

I encounter this issue on both physical and emulated devices:
Physical pixel 6 with api 36
Emulated pixel 7 with api 36 running Google Play Store services
Emulated pixel 7 with api 36.1 running Google Api’s services

In attempting to debug this issue I have found a workaround for now, but do not believe this is the expected process:
After logging in successfully I check if this is the first time the app has been launched on the device via a property in the sharedPrefs, and if it is I create a new credentials manager and replace the old one with it. I do not know why this works but the invalid_grant error is not encountered this way and no other errors or odd behaviors seem to occur.

Here is a code snippet of of how I create my CredentialsManager:

        val auth0 = Auth0.getInstance(clientID, domain)
        val authClient = AuthenticationAPIClient(auth0)
        val storage = SharedPreferencesStorage(context)

        credentialsManager = CredentialsManager(
            authClient,
            storage
        )

        Log.d("credentials", "New Credentials Manager:\n ${System.identityHashCode(credentialsManager)}")

Here is a code snippet of how I create the webAuthProvider

        val auth0 = Auth0.getInstance(clientID, domain)

        WebAuthProvider.login(auth0)
            .withScope("openid profile email offline_access")
            .withAudience(audience)
            .withRedirectUri(redirect)
            .start(context, object : Callback<Credentials, AuthenticationException> {

Auth0.Android version

3.10.0

Android version(s)

8.13.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugThis points to a verified bug in the code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions