Search code examples
androidkotlinretrofit2okhttpinterceptor

Is there a problem doing another API call inside interceptor in Android?


I have an issue where I am trying to refresh an access token inside my interceptor. I have read it is better to use an Authenticator for this issue, but the way my API works is that I get a 403 error for an unauthorized access token (not my design but gotta work with it).

So I am trying to call the API endpoint to get a new access token inside my interceptor but it seems like the second API call creates an OKHTTP Response without closing it.

override fun intercept(chain: Interceptor.Chain?): Response {

        var currentRequest = chain!!.request()
        val currentRequestResponse = chain.proceed( currentRequest )

        if ( currentRequestResponse.code() >= HTTP_ERROR_CODE && isNotLoginRequest( chain ) ) {

            try {

                // we check the response code, if there is 403 code we need to relog the user
                // before executing the request
                // try to reconnect the user with synchronous request


                val userManager = UserManager.getInstance()

                val clientId = getQueryParameter(UserService.CLIENT_ID_QUERY_KEY, currentRequest)
                val redirectUri = getQueryParameter(UserService.REDIRECT_URI_QUERY_KEY, currentRequest)
                val clientSecret = getQueryParameter(UserService.CLIENT_SECRET_QUERY_KEY, currentRequest)

                // we get a new access token with a synchronous request
                val accessToken = userManager.refreshToken(clientId, clientSecret, redirectUri)

                currentRequest = rebuildRequestWithNewToken( accessToken, currentRequest )

                return chain.proceed( currentRequest )

            } catch (e: Throwable) {

                e.printStackTrace()
            }
        }

        return currentRequestResponse
    }

I believe the problem comes from the userManager.refreshToken which is the API call to get the new access token.

Here is the error I receive:

java.lang.IllegalStateException: cannot make a new request because the previous response is still open: please call response.close()


Solution

  • You can make the refresh token call inside the network interceptor like this

    if (response.code() == 403) {
                try {
                    val body = RequestBody.create(contentType, "")
    
                    val authRequest = request.newBuilder()
                            .setDefaultHeaders()
                            .addHeader("Authorization", "Your token")
                            .url(refreshtokenurl)
                            .post(body)
                            .build()
                    val tokenRefreshResponse = chain.proceed(authRequest)
                    if (tokenRefreshResponse.code() == 401 || tokenRefreshResponse.code() == 403) {
                       //error in refreshing token
                    } else if (tokenRefreshResponse.code() == 200) {
                       //save the new token and refresh token in preference and continue with the earlier request
                        currentRequestResponse = chain.proceed(currentRequest.newBuilder()
                                    .setDefaultHeaders()
                                    .addHeader(your header)
                                    .build())
                    }
                } catch (e: Exception) {
    
                }
    
            }