'How to handle refresh token for Parallel API Calls

I have multple API calls in Parallel Mod in one View, and when token is Expired all of them got 401, and authenticator refreshing token for all of them. how should I protect myself against this. I've heard about mutex but I don't really know how to do it with it. Is it better to authorize the 401 using Authenticator or interceptor or are there any other ways to handle this?

My authenticator class below.

class TokenAuthenticator( 
private val authenticationRepository: AuthenticationRepository, 
private val userAndTokenRepository: UserAndTokenRepository, 
private val crashlyticsManager: CrashlyticsManager 
) : Authenticator {

override fun authenticate(route: Route?, response: Response): Request? {
    return runBlocking {
        getUpdatedToken()?.let { token ->
            userAndTokenRepository.storeToken(token)
            response.request.newBuilder()
                .header(HEADER_AUTHORIZATION, "$AUTHORIZATION_TYPE ${token.accessToken}")
                .build()
        }
    }
}

private suspend fun getUpdatedToken(): Token? {
    return withContext(Dispatchers.IO) {
        val accessTokenResult = authenticationRepository.refresh(
            userAndTokenRepository.getEmail() ?: "",
            userAndTokenRepository.getRefreshToken() ?: ""
        )
        when (accessTokenResult) {
            is Result.Success -> accessTokenResult.data
            is Result.Failure -> {
                crashlyticsManager.recordException(Exception(accessTokenResult.error))
                null
            }
        }
    }
 }
}


Solution 1:[1]

This has a good example, just using synchronized, since you really only want one to refresh the token, and other should wait.

https://blog.coinbase.com/okhttp-oauth-token-refreshes-b598f55dd3b2

class AccessTokenAuthenticator(
    private val tokenProvider: AccessTokenProvider
) : Authenticator {

    override fun authenticate(route: Route?, response: Response): Request? {
        // We need to have a token in order to refresh it.
        val token = tokenProvider.token() ?: return null

        synchronized(this) {
            val newToken = tokenProvider.token()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Yuri Schimke