Aslam Hossin
07/13/2023, 6:24 PMclass TokenRepository(private val settings: Settings) {
private val accessTokenKey = "AccessToken"
private val refreshTokenKey = "RefreshToken"
private val userIdKey = "UserId"
private fun fetchRefreshToken() = settings.getStringOrNull(refreshTokenKey)
fun saveTokens(authResponse: AuthResponse) {
settings.putString(accessTokenKey, authResponse.accessToken)
settings.putString(refreshTokenKey, authResponse.refreshToken)
settings.putInt(userIdKey, authResponse.userId)
}
fun saveTokens(bearerTokens: BearerTokens) {
settings.putString(accessTokenKey, bearerTokens.accessToken)
settings.putString(refreshTokenKey, bearerTokens.refreshToken)
}
fun fetchUserId() = settings.getInt(userIdKey, 0)
fun fetchBearerTokens(): BearerTokens? {
val accessToken = settings.getStringOrNull(accessTokenKey)
val refreshToken = settings.getStringOrNull(refreshTokenKey)
return if (accessToken != null && refreshToken != null) {
BearerTokens(accessToken, refreshToken)
} else null
}
fun destroyTokens() = settings.clear()
suspend fun refreshToken(): BearerTokensDTO =
HttpClient {
defaultRequest {
url {
protocol = URLProtocol.HTTP
host = OpMConfig.BASE_URL
path(ApiVersion.Version.versionName)
}
header(HttpHeaders.ContentType, ContentType.Application.Json)
}
install(Logging) {
logger = HttpClientLogger
level = LogLevel.ALL
}
install(ContentNegotiation) {
json(NetworkModule.nonStrictJson)
}
}.post(ApiEndpoint.RefreshToken.path) {
setBody(mapOf(ApiField.RefreshToken to fetchRefreshToken()))
}.parse()
}
object NetworkModule : KoinComponent {
const val BASE_CLIENT = "BaseHttpClient"
const val AUTH_CLIENT = "AuthHttpClient"
val nonStrictJson = Json { isLenient = true; ignoreUnknownKeys = true }
private val tokenRepository: TokenRepository by inject()
private val baseHttpClient = HttpClient {
defaultRequest {
url {
protocol = URLProtocol.HTTP
host = BASE_URL
path(Version.versionName)
}
header(HttpHeaders.ContentType, ContentType.Application.Json)
}
install(Logging) {
logger = HttpClientLogger
level = LogLevel.ALL
}
install(ContentNegotiation) {
json(nonStrictJson)
}
}
private val authHttpClient = baseHttpClient.config {
install(Auth) {
bearer {
sendWithoutRequest { true }
loadTokens { tokenRepository.fetchBearerTokens() }
refreshTokens {
tokenRepository.refreshToken().toBearerTokens().also {
tokenRepository.saveTokens(it)
}
}
}
}
}
val networkClient = module {
single(named(BASE_CLIENT)) { baseHttpClient }
single(named(AUTH_CLIENT)) { authHttpClient }
}
}
s3rius
07/13/2023, 7:19 PMauthClient.config {}
actually creates and returns a new instance and configures that one. The old instance stays as-is.
So in updateAuthClientHeader
you would have to authClient = authClient.config { .. }.
I just scrolled through the code, but I'm guessing that's the problem.
However, the OAuth plugin can attach the header all by itself.
I think you can just remove the updateAuthClientHeader
function and add this to the initial config bearer { ...; sendWithoutRequest { true } }
This sendWithoutRequest will tell the client to attach the bearer header to all requests (which is fine since it's your authClient). If you don't set it, it will always try the request and only re-try it with a bearer token if the server responds 401.Aslam Hossin
07/14/2023, 2:31 AMJacob Ras
07/14/2023, 8:35 AMAslam Hossin
07/14/2023, 10:49 AM