I am using OkHttp
in my android application with several async requests. All requests require a token to be sent with the header. Sometimes I need to refresh th
Use a singleton Authenticator
Make sure the method you use to manipulate the token is Synchronized
Count the number of retries to prevent excessive numbers of refresh token calls
Here is a sample in Kotlin
@SingleTon
class TokenAuthenticator @Inject constructor(
private val tokenRepository: TokenRepository
) : Authenticator {
override fun authenticate(route: Route?, response: Response): Request? {
return if (isRequestRequiresAuth(response)) {
val request = response.request()
authenticateRequestUsingFreshAccessToken(request, retryCount(request) + 1)
} else {
null
}
}
private fun retryCount(request: Request): Int =
request.header("RetryCount")?.toInt() ?: 0
@Synchronized
private fun authenticateRequestUsingFreshAccessToken(
request: Request,
retryCount: Int
): Request? {
if (retryCount > 2) return null
tokenRepository.getAccessToken()?.let { lastSavedAccessToken ->
val accessTokenOfRequest = request.header("Authorization") // Some string manipulation needed here to get the token if you have a Bearer token
if (accessTokenOfRequest != lastSavedAccessToken) {
return getNewRequest(request, retryCount, lastSavedAccessToken)
}
}
tokenRepository.getFreshAccessToken()?.let { freshAccessToken ->
return getNewRequest(request, retryCount, freshAccessToken)
}
return null
}
private fun getNewRequest(request: Request, retryCount: Int, accessToken: String): Request {
return request.newBuilder()
.header("Authorization", "Bearer " + accessToken)
.header("RetryCount", "$retryCount")
.build()
}
private fun isRequestRequiresAuth(response: Response): Boolean {
val header = response.request().header("Authorization")
return header != null && header.startsWith("Bearer ")
}
}