Fetch access token Synchronously

Hi all,
I was using OKHttp Authenticator earlier to update the expired tokens. When the API fails with 401, I make a synchronous call to refresh the token. when the token is refreshed, I update the header with new token and return the new request with new token attached.
Similar to Problem Solved 2: Access Token refresh with Okhttp Authenticator | by Sandeep Tengale | Medium

When I implemented AuthO, there is no way to fetch the access token synchronously.
I am using

credentialsManager.getCredentials(new BaseCallback<Credentials, CredentialsManagerException>() {
    onSuccess(Credentials cred){
    }
    onFailure(){
    }
}

which is asynchronous. The authenticator needs to be synchronous as it needs to return a request.

This is my authenticator:

synchronized Request authenticate(@Nullable Route route, @NonNull Response response) {
        Objects.requireNonNull(response, "Response");
        if(retries++ <= 0)
            lockManager.refreshToken(credentials -> {
                if(credentials.getAccessToken() != null){
                    Log.d(TAG, "authenticate: token updated "+credentials.getAccessToken());

                    sessionContext.setAccessToken(credentials.getAccessToken());
                    retries = 0;
                }
                if(credentials.getRefreshToken() != null){
                    sessionContext.setRefreshToken(credentials.getRefreshToken());
                }
            });
        else if(retries > 5) {
            Log.d(TAG, "authenticate: more than 5 tries giving up");
            return null;
        }

        String authHeader = String.format("%s %s", AppConstants.APIHeaders.AUTHORIZATION_VALUE,
                sessionContext.getAccessToken());
        Request request = response.request().newBuilder()
                .header(AppConstants.APIHeaders.AUTHORIZATION, authHeader)
                .build();
        return request;

    }
}

Here I am just retrying the request 5 times before giving up which seems like a hack to me. Is there a change listener which I can attach to the credential manager to get updates of the token changes??

I went through all the examples I could find, but in everything, the API call is being made after fetching the access token.

Please let me know the right way to do the access token refresh issue when I receive a 401 response.

FYI I already went through this:
https://auth0.com/docs/architecture-scenarios/mobile-api/mobile-implementation-android

2 Likes

Honestly just some kind of canonical or go-to method to get the auth0 credentials into okHttp would be a frekaing lifesaver

According to the documentation, getCredentials should always return valid credentials. Therefore, it should not be necessary to implement an Authenticator, since Auth0 is taking care of refreshing the tokens inside the getCredentials call.

All you need to do is call getCredentials every time you’re making a call and pass the result to the header. For that, you still need to make the call “synchronous”. But that is entirely possible with Kotlin Coroutines:

suspend fun getAccessToken(): String {
        val credentials = suspendCoroutine<Credentials> { continuation ->
            credentialsManager.getCredentials(object : Callback<Credentials, CredentialsManagerException> {
                override fun onSuccess(result: Credentials) {
                    // Use credentials
                    continuation.resume(result)
                }

                override fun onFailure(error: CredentialsManagerException) {
                    // No credentials were previously saved or they couldn't be refreshed
                    continuation.resumeWithException(UnauthorizedException())
                }
            })
        }
        return credentials.accessToken
    }

Supposing OkHttp’s intercept() is being called on a background thread, you can call this function inside your interceptor like this:

  runBlocking {
            request.addHeader("Authorization", "Bearer ${LoginManager.getAccessToken()}")
        }
3 Likes

Thanks for sharing that with the rest of community!