Skip to content

Instantly share code, notes, and snippets.

@zern3w
Created June 25, 2019 11:27
Show Gist options
  • Save zern3w/3867522f4992e02f177e5a28fc2fde40 to your computer and use it in GitHub Desktop.
Save zern3w/3867522f4992e02f177e5a28fc2fde40 to your computer and use it in GitHub Desktop.
import android.os.SystemClock
import android.util.Log
import okhttp3.Interceptor
import okhttp3.Response
import java.io.IOException
class RequestInterceptor(private val tokenStore: TokenStore) : Interceptor {
private val oauthService by lazy { ServiceGenerator.createAuthService() }
private var isRefreshing = false
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(chain.request())
// Checking for unauthorized
if (response.code() == 401) {
Log.d(javaClass.simpleName, "Unauthorized request was intercepted")
// Wait until refresh token is finished
if (isRefreshing){
Log.d(javaClass.simpleName, "Token is refreshing ...")
do {
Log.d(javaClass.simpleName, "Sleep for ${SLEEP_TIME/1000} seconds ...")
SystemClock.sleep(SLEEP_TIME)
} while (isRefreshing)
return chain.proceed(chain.request())
}
val refreshToken = tokenStore.getRefreshToken()
if (!refreshToken.isNullOrEmpty()){
// Perform synchronous refresh token
val refreshResponse = refreshToken(refreshToken!!)
if (refreshResponse != null) {
when {
// NetworkInterceptor will take care of adding authorization header after refreshing token has finished
refreshResponse.code() == 200 -> return chain.proceed(chain.request())
refreshResponse.code() == 401 -> logout()
else -> return refreshResponse
}
}
}
}
return response
}
private fun refreshToken(refreshToken: String): Response? {
isRefreshing = true
var failedAttempt = 0
var response: Response? = null
do {
Log.d(javaClass.simpleName, "Refreshing Token")
val call = oauthService.refreshToken("refresh_token", refreshToken)
try {
val requestResponse = call.execute()
response = requestResponse.raw()
if (requestResponse.isSuccessful){
var accessToken = requestResponse.body()
if (accessToken != null){
Log.d(javaClass.simpleName, "Refresh Token success")
setActiveToken(accessToken.accessToken, accessToken.refreshToken)
isRefreshing = false
return response
}else{
failedAttempt += 1
}
}else{
failedAttempt += 1
}
} catch (e: IOException) {
failedAttempt += 1
e.printStackTrace()
}
} while (failedAttempt < MAX_ATTEMPT)
isRefreshing = false
return response
}
private fun setActiveToken(accessToken: String?, refreshToken: String?) {
if (!accessToken.isNullOrEmpty() && !refreshToken.isNullOrEmpty()) {
tokenStore.saveToken(accessToken!!)
tokenStore.saveRefreshToken(refreshToken!!)
tokenStore.notifiyTokenUpdate(accessToken, refreshToken)
}
}
private fun logout() {
Log.d(javaClass.simpleName, "Refresh Token failed, perform force logout")
}
companion object {
private const val MAX_ATTEMPT = 3
private const val SLEEP_TIME: Long = 3*1000 // 3 Seconds
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment