-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RefreshTokenPlugin: excecution is locked when updateTokenHandler gets 401 error #205
Comments
Possible solution - add class RefreshTokenPlugin(
private val updateTokenHandler: suspend () -> Boolean,
private val isCredentialsActual: (HttpRequest) -> Boolean,
private val needSkipRequest: (HttpRequest) -> Boolean,
) {
class Config {
var updateTokenHandler: (suspend () -> Boolean)? = null
var isCredentialsActual: ((HttpRequest) -> Boolean)? = null
var needSkipRequest: (HttpRequest) -> Boolean = { false }
fun build() = RefreshTokenPlugin(
updateTokenHandler = updateTokenHandler
?: throw IllegalArgumentException("updateTokenHandler should be passed"),
isCredentialsActual = isCredentialsActual
?: throw IllegalArgumentException("isCredentialsActual should be passed"),
needSkipRequest = needSkipRequest,
)
}
companion object Plugin : HttpClientPlugin<Config, RefreshTokenPlugin> {
private val refreshTokenHttpPluginMutex = Mutex()
override val key = AttributeKey<RefreshTokenPlugin>("RefreshTokenPlugin")
override fun prepare(block: Config.() -> Unit) = Config().apply(block).build()
override fun install(plugin: RefreshTokenPlugin, scope: HttpClient) {
scope.receivePipeline.intercept(HttpReceivePipeline.After) {
if (subject.status != HttpStatusCode.Unauthorized || plugin.needSkipRequest(subject.request)) {
proceedWith(subject)
return@intercept
}
refreshTokenHttpPluginMutex.withLock {
// If token of the request isn't actual, then token has already been updated and
// let's just to try repeat request
if (!plugin.isCredentialsActual(subject.request)) {
val requestBuilder = HttpRequestBuilder().takeFrom(subject.request)
val result: HttpResponse = scope.request(requestBuilder)
proceedWith(result)
return@intercept
}
// Else if token of the request is actual (same as in the storage), then need to send
// refresh request.
if (plugin.updateTokenHandler.invoke()) {
// If the request refresh was successful, then let's just to try repeat request
val requestBuilder = HttpRequestBuilder().takeFrom(subject.request)
val result: HttpResponse = scope.request(requestBuilder)
proceedWith(result)
} else {
// If the request refresh was unsuccessful
proceedWith(subject)
}
}
}
}
}
} Example usage: needSkipRequest = { request ->
request.call.request.url.encodedPath.endsWith("/auth/refresh")
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
updateTokenHandler
usually contains a request for refreshingaccessToken
, but in some APIs this request can get401 Unauthorized
error (for example, whenrefreshToken
is outdated as well). In this caseRefreshTokenPlugin
gets locked by mutex, and no other requests can be executedThe text was updated successfully, but these errors were encountered: