Auto-refresh auth token on 401
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package com.android.trisolarispms.data.api
|
package com.android.trisolarispms.data.api
|
||||||
|
|
||||||
import com.google.firebase.auth.FirebaseAuth
|
import com.google.firebase.auth.FirebaseAuth
|
||||||
|
import okhttp3.Authenticator
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.logging.HttpLoggingInterceptor
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
@@ -18,7 +19,7 @@ object ApiClient {
|
|||||||
val authInterceptor = Interceptor { chain ->
|
val authInterceptor = Interceptor { chain ->
|
||||||
val original = chain.request()
|
val original = chain.request()
|
||||||
val token = try {
|
val token = try {
|
||||||
kotlinx.coroutines.runBlocking { tokenProvider.token() }
|
kotlinx.coroutines.runBlocking { tokenProvider.token(forceRefresh = false) }
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
@@ -32,12 +33,28 @@ object ApiClient {
|
|||||||
chain.proceed(request)
|
chain.proceed(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val authenticator = Authenticator { _, response ->
|
||||||
|
if (response.code != 401) return@Authenticator null
|
||||||
|
if (response.request.header("X-Auth-Retry") == "true") return@Authenticator null
|
||||||
|
val newToken = try {
|
||||||
|
kotlinx.coroutines.runBlocking { tokenProvider.token(forceRefresh = true) }
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
if (newToken.isNullOrBlank()) return@Authenticator null
|
||||||
|
response.request.newBuilder()
|
||||||
|
.header("Authorization", "Bearer $newToken")
|
||||||
|
.header("X-Auth-Retry", "true")
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
val logging = HttpLoggingInterceptor().apply {
|
val logging = HttpLoggingInterceptor().apply {
|
||||||
level = if (enableLogging) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
|
level = if (enableLogging) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
val client = OkHttpClient.Builder()
|
val client = OkHttpClient.Builder()
|
||||||
.addInterceptor(authInterceptor)
|
.addInterceptor(authInterceptor)
|
||||||
|
.authenticator(authenticator)
|
||||||
.addInterceptor(logging)
|
.addInterceptor(logging)
|
||||||
.connectTimeout(30, TimeUnit.SECONDS)
|
.connectTimeout(30, TimeUnit.SECONDS)
|
||||||
.readTimeout(30, TimeUnit.SECONDS)
|
.readTimeout(30, TimeUnit.SECONDS)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
package com.android.trisolarispms.data.api
|
package com.android.trisolarispms.data.api
|
||||||
|
|
||||||
interface AuthTokenProvider {
|
interface AuthTokenProvider {
|
||||||
suspend fun token(): String?
|
suspend fun token(forceRefresh: Boolean = false): String?
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import kotlinx.coroutines.tasks.await
|
|||||||
class FirebaseAuthTokenProvider(
|
class FirebaseAuthTokenProvider(
|
||||||
private val auth: FirebaseAuth
|
private val auth: FirebaseAuth
|
||||||
) : AuthTokenProvider {
|
) : AuthTokenProvider {
|
||||||
override suspend fun token(): String? {
|
override suspend fun token(forceRefresh: Boolean): String? {
|
||||||
val user = auth.currentUser ?: return null
|
val user = auth.currentUser ?: return null
|
||||||
return user.getIdToken(false).await().token
|
return user.getIdToken(forceRefresh).await().token
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user