Migrating 0.9.2 → 1.0.0-beta-3

Estimated reading time: 23 minutes

Table of contents:


This is the third beta of Ktor. And the first version of Ktor using Kotlin 1.3.0 and kotlinx.coroutines 1.0.0 final versions!

Published 29 Oct 2018

Version bumps:

  • Kotlin: 1.3.0-rc-146 -> 1.3.0
  • Kotlinx IO: 0.1.0-alpha-25-rc13 -> 0.1.0-beta-1
  • Kotlinx Coroutines: 1.0.0-RC1 -> 1.0.0
  • Kotlinx Serialization: 0.8.2-rc13 -> 0.9.0
  • AtomicFU: 0.11.11 -> 0.11.12


  • Add js support in kotlinx.serialization feature (commit) (Close #666)
  • Avoid blocking PRNG (commit)
  • Improve OAuth2 diagnostics for token acquisition failure (#550)
  • Lookup serializer with .serializer (commit)
  • Added a bunch of KDocs and clarified old ones


  • Fix handling auth errors (#676)


  • Remove the redundant flag from ApacheHttpRequest (commit)

How to try

You need to use Kotlin 1.3.0 or later. That version should be available at Maven Central and jcenter:

buildscript {
    ext.kotlin_version = '1.3.0'

You will also need to use the Kotlin 1.3 inside IntelliJ IDEA.


This is the second beta of Ktor.

Published 24 Oct 2018

Version bumps:

  • Kotlin: 1.3.0-rc-131 -> 1.3.0-rc-146
  • Kotlinx IO: 0.1.0-alpha-19-rc13 -> 0.1.0-alpha-25-rc13
  • Kotlinx Coroutines: 0.30.2-eap13 -> 1.0.0-RC1
  • AtomicFU: 0.11.10-eap13 -> 0.11.11

Major changes:

Marked as experimental:

  • Mark locations API as experimental (commit)
  • Introduce stopServerOnCancellation instead of the cancellation helper (commit)


  • Rename nextNonce to generateNonce (commit)


  • Introduce application coroutine scope (commit)
  • Introduce ability to specify an coroutine scope for embedded server (commit)
  • ktor-client: Add HttpsURLConnection config to AndroidEngineConfig (commit)
  • ktor-client: Add proxy to AndroidEngineConfig (commit)
  • Add KotlinxSerializer.register() with explicit KSerializer (commit)
  • Add default serializers to KotlinxSerializer (commit)
  • Add KotlinxSerializer register() to use reified generics to set mapper (commit)
  • Introduce href extension function for the Locations feature (#597)

Minor changes:

  • Restrict Location annotation targets, allow on a typealias (#539)
  • Remove default connector on port 80 (#670)
  • Do not disable Kotlin Native devirtualization (commit)


  • Improve JWT diagnostics (#664)
  • Improve OAuth2 diagnostics for token acquisition failure (#550)
  • Replace Unconfined in blocking servlets implementation (commit)
  • Improve nextNonce strength (now called generateNonce) (commit)
  • Improve error handling of KotlinxSerializer (commit)


  • Fix multipart part disposal on Windows (commit)
  • Fix websocket IDLE timeout on Jetty (commit)
  • Fix broken compression that caused channel to be closed too early (commit)
  • Properly construct request headers in JS engine (#665)
  • Fix engine’s suite socket connect timeout (commit)
  • Fix embedded tomcat engine stop (commit)
  • Eliminate using Unconfined for reading from file (fixes selector infinite loop) (commit)
  • Fix StatusPages to handle child job failures (#646)


  • Fix experimental annotation in benchmark (commit)

How to try

You need to include kotlin-eap repository and use Kotlin 1.3.0-rc-146 or later:

buildscript {
    ext.kotlin_version = '1.3.0-rc-146'

    repositories {
        // ...
        maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }

repositories {
    // ...
    maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
    maven { url 'https://dl.bintray.com/kotlin/kotlinx' }
    maven { url 'https://dl.bintray.com/kotlin/ktor' }

You will also need to use the Early Access Preview 1.3 inside IntelliJ IDEA.

To do so, Tools -> Kotlin -> Configure Kotlin Updates and as Update Channel, select Early Access Preview 1.3 and install that version of the plugin.

DevelopmentEngine to EngineMain

We have renamed the DevelopmentEngine classes to EngineMain, and you will have to update your application.conf configuration files.

The DevelopmentEngine classes were used as entry point for Ktor applications. It loaded the application.conf and parsed CLI parameters, in addition to create an embedded server and loading the specified module.

The problem with DevelopmentEngine was that it was confusing since some people identified Development as opposed to Production.

The new name reflects that it serves as entry point of the application, and that it is independent on the environment being suitable for both: development and production.


This is the first beta of Ktor! This page includes changes from the alpha-2, alpha-3 and beta-1.

Published 15 Oct 2018

Version bumps:

  • Kotlinx IO: 0.1.0-alpha-17-rc13 -> 0.1.0-alpha-19-rc13


  • Add js client engine (commit)
  • Introduce client Send feature. Migrate HttpRedirect (commit)
  • Introduce ExpectSuccess feature (commit)


  • URLBuilder now distinguishes between a port not being specified and falling back to the defaultPort for the protocol (#561)
  • Use UTF-8 encoding as fallback in client response config (commit)
  • Use default port in client builders by default (port 0 now means the default port for the protocol)
  • Provide user-defined function to configure Netty’s HttpServerCodec (#629) fixes #580
  • Add missing HttpClient constructor (commit)
  • Add MockEngine content test (commit)
  • Add convenience methods to the WebSockets API (commit)
  • Prepare to migration to coroutines 1.0.0-RC (#642)
  • Use client status message from engine response (commit)


  • Fix TLS decryptor loop bug and reduce garbage (commit)
  • Fix escapeHTML utility function (commit)
  • Fix client HttpSend loop to not exit if a call has been changed (commit)
  • Fix broken normalizeAndRelativize, add documentation (commit)
  • Fix cookies case sensitive (commit)
  • Fix cookies and parameters duplication (commit)

Performance improvements:

  • Improve internal utility ByteBuffer.moveTo (commit)


  • Improve documentation, API cleanup, introduce experimental annotation (commit)

Minor and cleanups:

  • Eliminate suspend function with CoroutineScope receiver (commit)
  • Add more words to spell checker dictionary (commit)
  • Eliminate unreachable code warning (commit)
  • Fix test packets in client (commit)
  • Drop Apache URIBuilder (commit)
  • Fix Test names (commit)
  • Fix .editorconfig to append trailing newline (commit)

How to try

You need to include kotlin-eap repository and use Kotlin 1.3.0-rc-131 or later:

buildscript {
    ext.kotlin_version = '1.3.0-rc-131'

    repositories {
        // ...
        maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }

repositories {
    // ...
    maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
    maven { url 'https://dl.bintray.com/kotlin/kotlinx' }
    maven { url 'https://dl.bintray.com/kotlin/ktor' }

You will also need to use the Early Access Preview 1.3 inside IntelliJ IDEA.

To do so, Tools -> Kotlin -> Configure Kotlin Updates and as Update Channel, select Early Access Preview 1.3 and install that version of the plugin.


Ktor 1.0.0-alpha-1 is the initial pre-release version that preludes the 1.0. This version is the first one using Kotlin 1.3.0-rc-131, and bumps the kotlinx.coroutines version to 0.30.2-eap13. As an important change, Ktor now uses the structured concurrency from kotlinx.coroutines. In addition it adds

Published 9 Oct 2018

Version Bumps:

  • Kotlin: 1.2.70 -> 1.3.0-rc-131
  • Kotlinx IO: 0.1.0-alpha-4 -> 0.1.0-alpha-17-rc13
  • Kotlinx Coroutines: 0.25.0 -> 0.30.2-eap13
  • Atomic FU: 0.11.3 -> 0.11.10-eap13

Major changes:

Deprecations, renames and API changes:

  • Increased some old deprecations to DeprecationLevel.ERROR
  • Deprecated ByteBufferBuilder
  • Renamed RoutingException -> LocationRoutingException
  • HttpMessageBuilder.contentLength() and HttpMessage.contentLength() now return Long
  • Remove some deprecated and changed to experimental internal APIs. (eg. WebSocketInternalAPI)
  • AndroidClientEngine is now @UseExperimental(InternalAPI::class)
  • Deprecated ApacheBackend typealias for Apache engine


  • Make default call pipeline discard request body content (Fixes #609, #574)
  • Fixes url path encoding
  • Fix server response logging after release
  • Make Cookie.matches ignore a leading dot in the domain



  • Unify mimetype + use random from the Kotlin 1.3 stdlib
  • Test Kotlin/Native on MacOS

Minor changes:

  • Some API documentation
  • Add editorconfig for external editors
  • Use kotlin.code.style=official

New coroutines

Since 1.0.0-alpha-1, Ktor is using the latest kotlinx.coroutines version that is using structured concurrency. Now each request has its own CoroutineScope and you can also use the GlobalScope.

For more information: https://github.com/Kotlin/kotlinx.coroutines/blob/master/docs/basics.md#structured-concurrency


Ktor 0.9.5 is a minor update, fixing some bugs, bumping some versions, and adding some minor stuff.

Published 19 Sep 2018

Version Bumps:

  • Kotlin: 1.2.61 -> 1.2.70

Minor potential breaking changes:

  • Client’s CookiesStorage.get, CookiesStorage.addCookie and HttpCookies.get now accepts the requestUrl instead of the host. Now the get returns a list of cookies.
  • Made HTTP Client extension method HttpRequest.takeFrom(builder: HttpRequestBuilder): HttpRequestBuilder. Now also sets the typed call attributes from the builder. into a member method. Shouldn’t be a source compatibility problem when using star imports * since it is in the same package.


  • HttpClient.config was not preserving the base configuration (#559)
  • Fixed path and query escaping and make it consistent with URLBuilder (#577).
  • Fixed setting charset encoding for non-text content types


  • Introduced CallId feature
  • Added MDC support to CallLogging feature

API Improvements:

  • Added shorthand client functions for HEAD, OPTIONS, PATCH and DELETE methods (#562)
  • HTTP Client: Added List<Cookie>.get(name: String): Cookie? shortcut.
  • HTTP Client: Added fun FormBuilder.append(key: String, filename: String, block: BytePacketBuilder.() -> Unit) to the FORM DSL.
  • URLBuilder’s parser improved (#553, #567)
  • Added respondOutputStream { } response function
  • Split Infrastructure phase into Monitoring and Features phases


  • Made AcceptAllCookiesStorage be the same for all the implementations.
  • Improved client’s cookie matching and processing

New http method shorcuts for the HTTP client

Before 0.9.5, when using the HTTP client and wanting to make a HEAD, OPTIONS, PATCH or DELETE request, you had to either use the HttpClient.request or the HttpClient.call.

As for 0.9.5, in addition to HttpClient.get and HttpClient.post there are now four more convenience methods HttpClient.head, HttpClient.options, HttpClient.patch and HttpClient.delete HTTP verbs.

Split Infrastructure phase into Monitoring and Features phases

In most of the cases, you should use the Features phase instead of the Infrastructure one:

intercept(ApplicationCallPipeline.Infrastructure) {
    // ...

would become:

intercept(ApplicationCallPipeline.Features) {
    // ...

CallId and MDC support in CallLogging

The CallLogging feature have been updated to allow to specify MDC (Mapped Diagnostic Context) keys + providers to be associated to a specific call/request regardless of the ThreadScheduler. The feature is implemented using kotlinx.coroutines ThreadContextElement, so it is transparent and works well with slf4j.

0.9.5 includes a new CallId feature that allows to identify calls from an ID. It allows to provide several methods for receiving or generating that Call Identifier, and also optionally allows to include the id as part of the response, for example as a header. The CallId is also associated to the MDC of the call, so the logs for a specific call can be identified and grouped together.


Ktor 0.9.4 fixes some bugs, bumps some versions, moves a few classes, improves the overall performance of the server. This version deprecate some APIs, introduce new ones, and includes a new multiplatform HTTP client (initially supporting JVM, iOS and Android).

This version is expected to be mostly source-code compatible with 0.9.3 except for the deprecate APIs.


Published 29 Aug 2018

Version Bumps:

  • Kotlin: 1.2.50 -> 1.2.61
  • kotlin-native -> 0.8.2
  • jetty_alpn_boot_version: 8.1.11.v20170118 -> 8.1.12.v20180117
  • coroutines_version: 0.23.3 -> 0.25.0
  • atomic_fu_version: -> 0.11.3
  • kotlinx_io_version: -> 0.1.0-alpha-4


Minor potentially breaking changes:

  • URL building: Set the default port too when changing the protocol
  • Prohibit appending unsafe headers to request headers
  • Client: the io.ktor:ktor-client-json artifact has been renamed to io.ktor:io.ktor:ktor-client-gson (to support a new JacksonSerializer)
  • Now all the Client JSON-related (ktor-client-json, ktor-client-gson and ktor-client-jackson) artifacts require the kotlinx.serialization and thus require the maven { url "https://kotlin.bintray.com/kotlinx" } repo to be included
  • Changed Date to GMTDate in some specific internal places
  • Internal Client HttpRequest, HttpResponse and HttpRequestData changes
  • Package io.ktor.content moved to io.ktor.http.content
  • Top-level encodeURLQueryComponent method is now a extension method of String fun String.encodeURLQueryComponent()
  • PartData.FileItem now requires a lambda with an Input, instead of an InputStream
  • Now PartData has a new element PartData.BinaryItem, thus might require an additional branch or an else to be exhaustive when used in a expression


  • Netty: fix write pipeline to not drop connection too early. Large responses are not completely sent with ‘Connection: close’ (#534)
  • Fixes CharBufferBuilder issue: CIO Responses with more than 2048 characters in header result in IndexOutOfBoundsException (#419)
  • Fix push promise headers order with Netty and HTTP/2
  • Eliminate sending transfer-encoding sending with Netty and HTTP/2
  • Fixed encoding issue with binary data in TestApplicationRequest.setBody
  • Fix native Deflater leak (#489)
  • Fix resourceResource to check for regular file to prevent failing later with folders (#490)
  • Fix StringIndexOutOfBoundsException in static resource resolution (#493)
  • Fixes: When config is passed via -config=<filename>, environment variables are not resolved (#374)
  • Fixes Client connection close in pipelining
  • TLS: Fix exception on expected channel close
  • Fix Jetty client engine response cancel
  • Compression: fix messages with predefined identity encoding
  • Fix HTTP 417 status message
  • Fix JWT error handling for missing keyId or broken token
  • CIO: fix duplicate content-length header handling
  • Fix CIO pipeline to not interrupt write pipeline. This was causing pipeline to be cancelled and 400 Bad Request response was lost
  • Fix closed byte channel error handling for WriteChannelContent
  • Fix CIO client joining
  • Fix race responding bytes that caused an empty response with Netty relates to issue #350
  • Avoid closing ServletOutputStream even in case of error
  • Suppress already completed AsyncContext error
  • Handle response cancel in Jetty client engine
  • Make SessionTransportTransformerEncrypt return null on failure
  • Fix client attributes evaluation


  • Use garbage-free headers API in Netty
  • Avoid unnecessary allocations in Pipeline#merge
  • Improve best function selection in ApplicationEngineEnvironmentReloading
  • Do not scan classpath on every HttpClient instantiation, provide better error message

Improvements to existing APIs:

  • JWK: add verify configuration with optional issuer
  • Url and URLBuilder improvements
  • Make TypeInfo a data class (#459) (#471)
  • Testing: Add advanced test exception logging

  • Add client form data and multipart support (#500)
  • Add HttpStatusCode constants for the status codes defined in RFC 2518 (WebDAV)

  • Add jetty server engine failed callback handler(http2)
  • Wrap Jetty channel fail into ChannelIOException
  • Wrap client exception from response pipeline with request and typeInfo

  • Add utility to append header value (such as content type)

  • Improve netty response pipeline for HTTP/2 case
  • Set default random algorithm from system provided

New features:

  • New multiplatform HTTP Client:
  • Add initial webjars feature (#498)
  • Add EngineAPI marker annotation
  • Add JacksonSerializer to HTTP Client
  • Client: Add HttpResponse.receive method
  • Client: Add default request configurator
  • Client: New way to configure or reconfigure the HttpClient Engine

Internal changes:

  • Internal: Update modules layout

New multiplatform HTTP Client

Starting with Ktor 0.9.4, there is a MPP HTTP Client included with Ktor.

In 0.9.4, the client is implemented for the JVM, Android and iOS.

We provide a sample of this feature as part of the ktor-samples repo: ktor-samples/client-mpp

You can read more about this feature in the Multiplatform HTTP Client page.

Reconfiguring the HttpClientEngineConfig

Prior to 0.9.4, you had to configure the HttpClient Engine by:

HttpClient(MyEngine.config {
    // ... config ...
}) {
    install {

Since 0.9.4, HttpClientConfig provides an engine method to reconfigure or configure the HttpClientEngineConfig:

HttpClient(MyEngine) {
    engine {
        // ... config ... 
    install {


Since 0.9.4, and after a period of deprecation, Ktor started to completely forbid to set contentType and contentLength headers directly. This is because those are bound to the OutgoingContent instances, that is the object describing the body of the response.

The respondText, respondBytes and other methods, allow you to set the Content-Type as an optional argument. And when using any subtype of OutgoingContent, you can set the contentType there.

For more information about this topic, check the Generating HTTP Responses page.


In some places (like Client HttpResponse) we were using Java’s Date class. Now we are using GMTDate instead.

Client HttpRequest, HttpResponse and HttpRequestData changes

Previously the HttpRequestData, had an attributes method to build an Attributes instance from another. Now it is a property instead. Attributes().apply { data.attributes(this) } would become data.attributes.

This change, affects, for example when implementing a HttpRequest:

override val attributes: Attributes = Attributes().apply { data.attributes(this) }
// -->
//override val attributes: Attributes = data.attributes

And the HttpResponse changed its requestTime and responseTime from java’s Date to io.ktor.util.date.GMTDate.


Ktor 0.9.3 fixes some bugs, bumps some versions, improves the overall performance of the server, and introduces new APIs and changes for some of them.

This version is expected to be mostly source-code compatible with 0.9.2 except for advanced use-cases related with kotlinx.coroutines and Ktor Raw sockets.


Published 26 Jun 2018

  • Improved WebSocket API
  • Websocket header Sec-WebSocket-Key is now optional
  • Fixed client cookies rendering to avoid x-enc
  • Fixed plain text client reader (#392)
  • Added EC support in CIO TLS (#394: ECDHE_RSA_AES256_SHA384, ECDHE_RSA_AES128_SHA256)
  • Fix client certificate validation
  • Introduced optional authentication
  • Added ApplicationCall as receiver for auth validate functions
  • Introduced call.respondBytes (#395)
  • Improved JWT support: multiple schemes, nullable issuer
  • Conversion service enum type diagnostics improved (#403)
  • Avoided using apos entity in HTML escaping as IE doesn’t support it (#400)
  • Converter support for java big numbers
  • Ability to add auth methods to existing feature on the fly
  • Improved auth header scheme and contents validation (#415)
  • Default charset for BasicAuth is now UTF-8 (#420)
  • Added ByteArrayContent.contentLength (#421)
  • Fixed headersOf case insensitive issue (#426)
  • Client deserialization improved by using type token
  • Ability to disable client default transformers
  • Explicit Accept header in client request
  • Turn on masking in client websockets (#423)
  • Fixed inverted PartialContent.Configuration.maxRangeCount check (#440)
  • Fixed uncaught UnsupportedMediaTypeException from receiveOrNull() (#442)
  • Fix multipart boundary header parsing
  • Upgraded jwks/jwt, applied RSA256 by default if unspecified (#434, #435)
  • Upgrade kotlinx.coroutines to 0.23.3
  • Upgrade Jetty version to 9.4.11.v20180605
  • Add client-mock-engine for testing purpose
  • HttpClient allows to use default available engine if not provided one
  • Upgrade kotlin to 1.2.50
  • Move ktor-samples to a separate repository (#340). https://github.com/ktorio/ktor-samples
  • Added client redirect feature *


WebSocket improvements

Now webSocketSession and webSocketRawSession return DefaultClientWebSocketSession and webSocket, ws and wss methods also receives a DefaultClientWebSocketSession and other methods return a ClientWebSocketSession.

This prevents having to cast to access some properties from the client session:

var DefaultWebSocketSession.pingInterval: Duration?
var DefaultWebSocketSession.timeout: Duration
val DefaultWebSocketSession.closeReason: Deferred<CloseReason?>
var DefaultClientWebSocketSession.masking: Boolean

HttpClient MockEngine

We had a MockEngine available internally for our tests for creating an HttpClient that was able to respond from our code programmatically without actually performing any request.

We have now exposed it in the io.ktor:ktor-client-mock artifact.

For example:

val mockEngine = MockEngine { call -> // suspend HttpRequest.(call: HttpClientCall) -> MockHttpResponse
    assertEquals("*/*", headers[HttpHeaders.Accept])

    MockHttpResponse(call, HttpStatusCode.OK, writer(ioCoroutineDispatcher) { channel.writeStringUtf8("HELLO") }.channel, headersOf(
        "X-Custom-Header" to listOf("value")

val client = HttpClient(mockEngine)

Inside the MockEngine block, you can assert things from the request, or decide how to generate a response based on the request.

HttpClient default Engine

Now you can instantiate a HttpClient by just HttpClient() without providing an engine. In that case it will use a ServiceLoader to find a suitable implementation based on the artifacts you have included.

HttpClient HttpRedirect feature

Now you can use the new client HttpRedirect feature to follow HTTP Location-based redirections. Read the documentation for more information.

HttpClient bug fixes

Now the HttpClient sends cookies in a standard way with one single header separating cookies by ;.

Reading an empty body as String with an Httpclient (HttpClient.get<String>) was causing a No transformation found: class io.ktor.client.engine.apache.ApacheHttpResponse -> class kotlin.String exception.

HttpClientEngine changes

HttpClientEngine now has a config field. So you will have to provide it in the case you have a custom engine.

HttpClient changes

Now the HttpClient sends an Accept header. If you have a test checking all the headers, you will need to update them.


TLS improvements

Ktor implements secure sockets using CIO, and the TLS available before 0.9.3 missed some cypher suites and encryption methods. We have updated it to support more required stuff.

Some errors you could encounter that now might be fixed:

  • Exception in thread "io-thread-1" io.ktor.network.tls.TLSException: Received alert during handshake. Level: FATAL, code: HandshakeFailure
  • Exception in thread "io-thread-2" io.ktor.network.tls.TLSException: Unsupported TLS handshake type CertificateRequest

aSocket breaking change

aSocket now requires a SelectorManager to be provided.

For example:


Of course, you can reuse the SelectorManager:

val mySocketSelector = ActorSelectorManager(ioCoroutineDispatcher)
val socket = aSocket(mySocketSelector).tcp()


WebSocket improvements

Before 0.9.3, when a WS request was made without the Sec-WebSocket-Key header, an IllegalArgumentException was thrown. Now it is optional.

Optional Authentication

Now it is possible to define a set of routes where you can provide authentication, but it is optional:

authenticate("method", optional = true) {
    // routes

The authenticate behaviour:

  • No authentication provided:
    • optional=false: challenge is performed
    • optional=true: route handler is executed with principal=null
  • Wrong credentials: Unauthorized
  • Valid credentials: route handler is executed with the principal generated from the authentication method

Missing call.respondBytes

Before 0.9.3 we had call.respondText but missed call.respondBytes. We have solved this.

Version bumps

Ktor now uses Kotlin 1.2.50 and kotlinx.coroutines 0.23.3.

kotlinx.coroutines has some breaking changes for advanced use-cases.


We have moved the generateCertificate function for generating self-signed certificates to the ktor-network-tls artifact: compile("io.ktor:ktor-network-tls:$ktor_version")

New ktor-samples repository

Before 0.9.3, we had several sample projects integrated directly in the ktor repository. They have grown, and we have moved them to their own repository: https://github.com/ktorio/ktor-samples


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 {
        // ...