Thread
#multiplatform
    Elka

    Elka

    1 year ago
    Hello, I am trying to build a multi-platform client that retries the request automatically when the token expired and 401 is returned from the server. For that I am using a sample code by moko-network. The refresh token api is being triggered but when it retries the  request using 
    request
     , I never get a 
    result
     as if some “deadlock” occurred.
    val requestBuilder = HttpRequestBuilder().takeFrom(context.request)
    val result: HttpResponse = context.client!!.request(requestBuilder)
    Any idea? Anyone implemented a RefreshToken feature that works with latest Ktor?
    r

    ribesg

    1 year ago
    I created a Ktor Client
    Feature
    for that.
    override fun install(feature: AuthFeature, scope: HttpClient) {
        scope.requestPipeline.intercept(HttpRequestPipeline.State) {
            if (context.usesAuthentication) {
                val token = feature.authTokenService.getToken() ?: return@intercept
                context.headers[HttpHeaders.Authorization] = "Bearer $token"
            }
        }
    
        val circuitBreaker = AttributeKey<Unit>("my-auth-request")
        scope.feature(HttpSend)!!.intercept { origin, context ->
            if (origin.response.status != HttpStatusCode.Unauthorized) return@intercept origin
            if (origin.request.attributes.contains(circuitBreaker)) return@intercept origin
            if (!feature.authTokenService.refreshToken()) return@intercept origin
            val token = feature.authTokenService.getToken() ?: return@intercept origin
            val request = HttpRequestBuilder()
            request.takeFromWithExecutionContext(context)
            request.headers[HttpHeaders.Authorization] = "Bearer $token"
            request.attributes.put(circuitBreaker, Unit)
            return@intercept execute(request)
        }
    }
    Elka

    Elka

    1 year ago
    Thanks @ribesg. But the
    takeFromWithExecutionContext
    is internal in Ktor
    1.4
    r

    ribesg

    1 year ago
    @Elka no it’s not.
    /**
         * Mutates [this] copying all the data from another [builder] using it as base.
         */
        @InternalAPI
        public fun takeFromWithExecutionContext(builder: HttpRequestBuilder): HttpRequestBuilder {
            executionContext = builder.executionContext
            return takeFrom(builder)
        }
    It’s
    public
    Elka

    Elka

    1 year ago
    The code you shared works thanks… The idea is that
    HttpSend
    Feature tracks the network call and cancels it when it is modified… Canceling it is necessary otherwise the new network call doesn’t kickstart.