:wave: I'm trying to make a companion client plug...
# ktor
j
👋 I'm trying to make a companion client plugin to the provided Auth plugin; one that, at will of the developer, can rewrite the response of the next request to return an HTTP 401 to trigger the provided Auth plugin logic and ultimately, help test that the integration works correctly. Is there an example I can look at for rewriting the response through a plugin but still have other plugins process the result? I've tried intercepting using the
sendPipeline
after
State
as well as intercepting
HttpSend
. Both had issues that didn't meet my expectations. What I expect to happen is: 1. Developer triggers my companion plugin through a debug tool of their choice so the next API call will return an HTTP 401 2. Developer triggers another API call and within one execution context: a. My companion plugin is triggered, rewriting the response to HTTP 401 b. The provided Auth plugin is triggered, with the refresh token logic being invoked & in Bearer token providers, the
access_token
&
refresh_token
are rotated c. The provided Auth plugin retries the original API with the new
access_token
and returns the response
rubber duck 1
✅ 1
When intercepting the
sendPipeline
, I get a
JobCancellationException
if I call
finish()
but if I don't, I get
java.lang.IllegalStateException: No request transformation found
When intercepting
HttpSend
, the Auth plugin doesn't process the HTTP 401 response and the exception just bubbles up normally
I was able to figure this out. Intercepting using
HttpSend
was what eventually worked. The issue I was running into was my companion Plugin was installed before the Auth plugin so when the HTTP 401 returned back up the interceptor chain, the Auth plugin was never included, hence why the exception was normally rethrown to the caller
Copy code
@OptIn(InternalAPI::class)
override fun install(plugin: ForceLogout, scope: HttpClient) {
    scope.plugin(HttpSend).intercept { context ->
        val shouldForceLogout = _shouldForceLogout.tryReceive().getOrNull() ?: false
        val call = if (shouldForceLogout) {
            val request = context.build()
            val response = HttpResponseData(
                statusCode = HttpStatusCode.Unauthorized,
                requestTime = GMTDate(),
                headers = Headers.Empty,
                version = HttpProtocolVersion.HTTP_1_1,
                body = ByteReadChannel(ByteArray(0)),
                callContext = request.executionContext
            )

            HttpClientCall(scope, request, response)
        } else {
            execute(context)
        }
        return@intercept call
    }
}
Where
_shouldForceLogout
is a
Channel<Boolean>
initialized with
Channel(1)