Search code examples
androidkotlinjwtretrofitrx-java

How to refresh the JWT token before calling the REST API in android? (Retrofit, Rx)


I am developing an android app using Kotlin, RxJava(RxKotlin), Retrofit.

Our service uses the JWT token.

It is not difficult to refresh the expired token, before sending a REST API.

But my problem is that...

Some UI calls multiple REST API in concurrently.

For example, 5 API Requests are sent to the server in MainActivity concurrently.

If the token was already expired, I will receive 5 errors with 401 http error code (token expired).

But in my case, I check whether the token is expired or not.

If the token is expired, I try to refresh the token.

So in this example, I send 5 requests for refreshing the token.

Then... I will get the 5 new JWT tokens...

My better idea is that...

Before I send the 5 REST requests, I can check whether the token is expired or not.

But the problem is... I have a lot of this kind of UIs.

So I need a more beautiful way.

I think this kind of code (checking the token before send requests in UI) can solve my problem.

But this code is redundant, boilerplate code...

I want to solve this problem with just one entrance.

I'm really sorry about my stupid English skill.


Solution

  • You can handle this situation centrally. OkHttpClient has a method, called authenticator(). When any response get unauthorized exception, it is called. An example is as following (I'm using kotlin here):

    OkHttpClient.Builder()
        .authenticator(object: Authenticator {
            override fun authenticate(route: Route?, response: Response): Request? {
                if(response.code == 401) {
                    // build retrofit client manually and call refresh token api
                    val refreshTokenService = retrofitClient.create(RefreshTokenService::class.java)
                    val refreshTokenResponse = refreshTokenService.refreshToken().execute()
                    val token = refreshTokenResponse.body().token
                    return response.request.newBuilder().header("Authorization", token).build()
                } else {
                    return response.request
                }                
            }
        })
    

    Add this client to retrofit. You have to change refresh token login inside this authenticator.