Skip to content

Build1 publisher2 min readPublished

Ktor 3.6.0 turns the auth provider into a value the route can type-check

The typed authentication module and Netty's HTTP/3 support both arrive experimental in Ktor 3.6.0, while the changes that touch code you already wrote are two deprecations and one client Accept-header setting.

The Engineer · Build desk

What happened

  • JetBrains released Ktor 3.6.0 with typed authentication, specialized OpenID Connect support and HTTP/3 for the Netty engine, all of it described in the announcement as experimental.
  • The typed authentication module also covers role-based access checks and anonymous users, alongside the type safety it adds for complex authentication setups.
  • Netty's HTTP/3 runs over QUIC, and its opt-in block tunes flow-control limits, UDP socket configuration and an idle timeout that JetBrains sets to 30 seconds in the sample.
  • The same engine can now serve cleartext h2c on one connector and HTTP/2 over TLS on another, switched on with enableH2c = true and enableHttp2 = true.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • decision The experimental label sets the scope of a sensible test: one service on a branch, with no promise the API arrives unchanged in the next minor release.
  • cost HTTP/3 costs more than a dependency bump. Because QUIC travels over UDP, whoever runs the load balancers and firewalls has to open the same port for UDP before the listener is reachable.
  • constraint A team that adopts none of the experimental features still has edits to schedule, because two functions their code may call today are now deprecated.
  • capability A service that currently hand-rolls token refresh and login redirects can test a library path for it, with sessions and a browser login interface included.

`authenticateWith(jwtAuth)` takes the provider, not its name. In the sample JetBrains published, `jwt<User>("my-jwt")` is assigned to a val, and the route block references that val, so the principal type travels with it: the sample reads `val user = call.principal`, with no type argument and no cast [5]. JetBrains describes the older arrangement as implicit typing bridging configuration to routes, and the new module as types that guarantee full type safety when working with complex authentication [2].

The elegant part of that syntax depends on Kotlin context parameters, according to the release post [4]. So the Kotlin version in your build constrains this upgrade as much as the Ktor version does.

The OpenID Connect plugin follows the same shape. `install(Oidc)` returns a value, `identityProvider("auth0")` declares an issuer and a `bearer` block with an audience set, and the route authenticates against `auth0.jwtBearer` before reading `call.principal.claims.subject` [6]. Providers are typed, and JetBrains says the plugin supports all OpenID Connect features in a typed way [6].

`enableHttp3 { }` does not stand alone. The documented order is an SSL connector first, then the opt-in block [8]; in the sample that connector listens on port 8443 [18]. QUIC is carried over UDP, which is why the block exposes UDP socket configuration at all [9], and it means 8443 has to be open for UDP on every hop in front of the service, not just TCP. JetBrains did not publish latency or throughput figures for the HTTP/3 path, so there is no vendor number here to test against your own traffic. Feedback is explicitly requested [10], which is the polite way of saying the API can still move.

The two deprecations are ordinary maintenance. `ApplicationCall.receive()` now accepts nullable types, and `receiveNullable()` is deprecated in consequence [13]. `respondHtmlPartial` replaces the deprecated `respondHtmlFragment` and uses `TagConsumer<Appendable>`, so it can emit partial HTML with every element `FlowContent` supports [14]. Parameter conversion also covers Kotlin's `Uuid`, `Byte` and the unsigned numeric types, which makes `val id: Uuid by call.parameters` work in a route [12].

On the client side, ContentNegotiation used to merge its registered content types into every `Accept` header [15]. With `ContentTypeMergeStrategy.SkipIfPresent`, an explicit `Accept` header wins, and requests without one still get the registered types added [15]. Anyone carrying an interceptor to undo that merge for one strict API can drop it. The cheap way to test the rest is a throwaway project from the generator at start.ktor.io with one protected route [16].

What to watch

  • Whether the typed authentication module and Oidc plugin keep their current API shape in 3.7 or churn before the experimental label comes off.
  • Whether JetBrains publishes measurements, or a production-support statement, for the Netty QUIC path.
  • Whether receiveNullable() and respondHtmlFragment get removal versions in a following release.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories