Migrating 0.9.1 → 0.9.2

Estimated reading time: 5 minutes

Ktor 0.9.2 fixes some bugs, improves the overall performance of the server, partially starts supporting JVM 9, and introduces new APIs and changes for some of them.

In this section, we will discuss how to convert existing code from 0.9.1 to 0.9.2.



  • New auth DSL, more suspendable functions (such as verify/validate)
  • RoutingResolveTrace for introspecting routing resolution process
  • HTTP client improvements and bugfixes (DSL, reconnect, redirect, cookies, websockets and more)
  • CIO http client pipelining support, chunked and more
  • CIO initial TLS support
  • Session authentication provider
  • OAuth2: introduced the ability to generate and verify state field
  • OAuth: fix scopes parameter to conform to RFC (#329)
  • OAuth2: fix bug with double scopes encoding (#370)
  • OAuth2: add the ability to intercept redirect URL
  • CORS: introduced the allowSameOrigin option
  • Auth: provide application call as receiver for validating functions (#375 and related)
  • Test host reworked, handleRequest reads the body and redirects the exceptions correctly
  • Servlets: fixed inputStream acquisition, fixed error handling
  • Java 9 compatibility improved (no modules yet)
  • Digest auth fixes (#380)
  • Log running connectors details for better development experience (#318)
  • Last-Modified header and related functionality to work in proper GMT time zone (#344)
  • IncomingContent is deprecated
  • URLBuilder fixes and improvements
  • Documentation improvements
  • Performance optimizations (Netty, CIO server backends)
  • CIO server improved stability
  • Encrypted session support (SessionTransportTransformerEncrypt)
  • Empty (null) model for freemarker (#291)
  • ContentNegotiation missing Accept header support (#317)


The biggest change in this version since 0.9.1, is authentication. Which has been redesigned:

In previous versions, you had to define an authentication block inside your Application or in a Route block, applying that authentication to all the subroutes matching that block.

That forced you to redefine several authentication providers, or in some cases that would force you to include authentication in unexpected routes.

authentication {
    basicAuthentication("ktor") { credentials ->
        if (credentials.password == "${credentials.name}123") UserIdPrincipal(credentials.name) else null

In 0.9.2, all the authentication mechanisms are defined at the Application level and have an optional name associated with them. Also, the method names for defining different mechanisms have changed. Now the new name of the authentication mechanism is part of the function call, and all its old parameters are defined using a DSL instead.

For example, to define a basic authentication myauth1, you should add this code to your application configuration:

install(Authentication) {
    basic(name = "myauth1") {
        realm = "Ktor Server"
        validate { credentials ->
            if (credentials.password == "${credentials.name}123") UserIdPrincipal(credentials.name) else null

And now you can create a Route node to apply the defined authentication to several routes using the authenticate method:

routing {
    authenticate("myauth1") {
        get("/authenticated/route1") {
            // ...
        get("/other/route2") {
            // ...
    get("/") {
        // ...

Authentication method name changes:

  • basicAuthenticationbasic
  • formAuthenticationform
  • digestAuthenticationdigest
  • jwtAuthenticationjwt
  • oauthAuthenticationoauth

You can read the new authentication page to see in detail how to use the new methods.

Test host reworked, handleRequest reads the body and redirects the exceptions correctly

The body property from TestApplicationRequest builder has been changed to a suspend setBody method:

handleRequest(HttpMethod.Post, "/") {
    addHeader("Accept", "text/plain")
    addHeader("Content-Type", "application/json")
    //body = """{"id":1,"title":"Hello, World!"}"""
    setBody("""{"id":1,"title":"Hello, World!"}""")
}.response.let { response ->
    // ...

Before 0.9.2, you had to call the method awaitCompletion in the response in the case the request was not generating the response body synchronously. In 0.9.2, the awaitCompletion method doesn’t exist, and it awaits completion automatically before returning the response.

IncomingContent deprecation

If you are using call.request.receiveContent().readChannel(), call.request.receiveContent().multiPartData() or call.request.receiveContent().inputStream(), you should consider changing it to call.receive<ByteReadChannel>(), call.receive<MultiPartData>() and/or call.receive<InputStream>() since it is deprecated and will be removed in future versions of Ktor.

Also, remember that InputStream is a synchronous API, so you should avoid it if possible.


In order to support WebSockets at the client side, we have changed some of the transitive dependencies and moved some classes: now there is a transitive dependency called ktor-http-cio that includes common WebSockets code among other things, which the ktor-websockets server feature depends on. But since it is a transitive dependency, that should be transparent to you.

Classes like WebSocketSession and Frame have been moved from the io.ktor.websocket package to the io.ktor.http.cio.websocket package.

import io.ktor.websocket.*

import io.ktor.http.cio.websocket.*


When building a new CIO HttpClient, while configuring the endpoint (it has been renamed from endpointConfig to endpoint, and now the property is immutable, so you have to mutate its contents):

Prior to 0.9.2:

val client = HttpClient(CIO.config { 
    endpointConfig = EndpointConfig().apply {    

After 0.9.2:

val client = HttpClient(CIO.config { 
    endpoint.apply {
        // ...