In my mobile app, I have a singleton Ktor HttpClient
with bearer authentication configured as such:
HttpClient(…) {
install(Auth) {
bearer {
sendWithoutRequest { requestBuilder -> some condition }
loadTokens(tokensStorage::getTokens)
refreshTokens {
performTokenRefresh(oldTokens.refreshToken)
}
}
}
}
Now consider the following flow:
tokenStorage
are not valid.HttpClient
loads the tokens from tokenStorage
and the request fails with a 401.HttpClient
tries to perform a refresh but it fails too because the refresh token is invalid.tokenStorage
.HttpClient
never tries to call loadTokens
anymore. Indeed, as far as I can see from the source code, loadTokens
is called only once and then never again.I found out a couple of ways to solve the issue.
The first one is to manually retrieve BearerAuthProvider
from the HttpClient
and clear the token myself like in the following snippet, but it seems like a hacky workaround:
httpClient.plugin(Auth).providers
.filterIsInstance<BearerAuthProvider>()
.first().clearToken()
Another one is to manually load the current token from my tokenStorage
in refreshToken
and disregard what get passed in [email protected]
:
refreshTokens {
val currentRefreshToken = tokenStorage.getTokens().refreshToken
performTokenRefresh(currentRefreshToken)
}
However this means that the client will do an unnecessary call to the refresh API, while having already a valid token pair (obtained from the login).
So my question is: is there a cleaner way to handle the situation? Am I misusing Ktor?
We clear it manually in 2 places: We have the "Logout" use case which will be always triggered no matter if user logout manually or by 401 kick out. Because we need to clear other cached data as well. So the first lines of that logout use case is to notify the http client that whatever tokens it cached are not valid anymore.
fun invalidateAuthTokens() {
val authProvider = httpClient.authProvider<BearerAuthProvider>()
requireNotNull(authProvider)
authProvider.clearToken()
}
You must make sure it will be called. We faced the case when we can open Login screen via app links, so potentially a user is logging while other user is still logged or the http client has empty tokens and doesn't know they are not valid. In that case we also needed to clear the cache on Login, so ktor's loadTokens{} called again when needed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With