Skip to content

Instantly share code, notes, and snippets.

@farshadrezaee
Last active April 15, 2020 23:15
Show Gist options
  • Save farshadrezaee/ca91fbec05511b852530031814e41652 to your computer and use it in GitHub Desktop.
Save farshadrezaee/ca91fbec05511b852530031814e41652 to your computer and use it in GitHub Desktop.
Handle refresh token with OkHttp
import android.util.Log
import okhttp3.Interceptor
import okhttp3.Response
class OAuthInterceptor(private val tokenEntry: TokenEntry) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
request = request.newBuilder()
.addHeader("Accept", "application/json")
.addHeader("Content-Type", "application/json")
.build()
if(tokenEntry.token != null){
request = request.newBuilder()
.addHeader("Authorization", tokenEntry.token)
.build()
}
val response = chain.proceed(request)
return response
}
}
import okhttp3.OkHttpClient
class OkHttpClientProvider private constructor() {
companion object {
private var okHttpClient: OkHttpClient? = null
fun provide(tokenEntry: TokenEntry): OkHttpClient {
if (okHttpClient == null) {
okHttpClient = OkHttpClient.Builder()
.authenticator(TokenAuthenticator(tokenEntry))
.addInterceptor(OAuthInterceptor(tokenEntry))
.build()
}
return okHttpClient!!
}
}
}
import com.google.gson.Gson
import okhttp3.*
import okhttp3.Request
class TokenAuthenticator(private val tokenEntry: TokenEntry) : Authenticator {
private var refreshResponse: Response? = null
override fun authenticate(route: Route?, response: okhttp3.Response): Request? {
val accessToken = tokenEntry.token
if (!isRequestWithAccessToken(response) || accessToken == null) {
return null
}
synchronized(this) {
val newAccessToken = tokenEntry.token
if (accessToken != newAccessToken) {
return response.request().newBuilder()
.addHeader("Authorization", tokenEntry.token)
.build()
}
val refreshGrantEntry = RefreshGrantEntry(tokenEntry.refresh)
refreshResponse = refreshToken(refreshGrantEntry)
if (refreshResponse == null || refreshResponse?.code() != 200) {
return response.request()
}
val newTokenEntry: TokenEntry = Gson().fromJson(refreshResponse?.body()?.string(), TokenEntry::class.java)
ApplicationResource.get().authStorage.save(newTokenEntry)
OkHttpClientProvider.reCreate(newTokenEntry)
return response.request().newBuilder()
.removeHeader("Authorization")
.addHeader("Authorization", newTokenEntry.token)
.build()
}
}
private fun refreshToken(refreshGrantEntry: RefreshGrantEntry): Response? {
val contentType = MediaType.parse("application/json , charset=utf-8")
val requestBody = RequestBody.create(contentType, Gson().toJson(refreshGrantEntry))
val request = Request.Builder()
.url("http://${APIs.BASE_API}" + "/api/oauth/token")
.post(requestBody)
.build()
try {
return OkHttpClientProvider.provide(tokenEntry).newCall(request).execute()
} catch (e: Exception) {
return null
}
}
private fun isRequestWithAccessToken(response: Response): Boolean {
val header = response.request().header("Authorization")
return header != null && header.startsWith("Bearer")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment