Ktor 3.0.3 Help

Form-based authentication

Form-based authentication uses a web form to collect credential information and authenticate a user. To create a web form in Ktor, you can use HTML DSL or choose between JVM template engines, such as FreeMarker, Velocity, and so on.

Add dependencies

To enable form authentication, you need to include the ktor-server-auth artifact in the build script:

implementation("io.ktor:ktor-server-auth:$ktor_version")
implementation "io.ktor:ktor-server-auth:$ktor_version"
<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-server-auth-jvm</artifactId> <version>${ktor_version}</version> </dependency>

Form-based authentication flow

The form-based authentication flow might look as follows:

  1. An unauthenticated client makes a request to a specific route in a server application.

  2. A server returns an HTML page that consists at least from an HTML-based web form, which prompts a user for a username and password.

  3. When a user submits a username and password, a client makes a request containing web form data (which includes the username and password) to a server.

    POST http://localhost:8080/login Content-Type: application/x-www-form-urlencoded username=jetbrains&password=foobar

    In Ktor, you need to specify parameter names used to fetch a username and password.

  4. A server validates credentials sent by a client and responds with the requested content.

Install form authentication

To install the form authentication provider, call the form function inside the install block:

import io.ktor.server.application.* import io.ktor.server.auth.* // ... install(Authentication) { form { // Configure form authentication } }

You can optionally specify a provider name that can be used to authenticate a specified route.

Configure form authentication

Step 1: Configure a form provider

The form authentication provider exposes its settings via the FormAuthenticationProvider.Config class. In the example below, the following settings are specified:

  • The userParamName and passwordParamName properties specify parameter names used to fetch a username and password.

  • The validate function validates a username and password. The validate function checks UserPasswordCredential and returns a UserIdPrincipal in the case of successful authentication or null if authentication fails.

  • The challenge function specifies an action performed if authentication fails. For instance, you can redirect back to a login page or send UnauthorizedResponse.

install(Authentication) { form("auth-form") { userParamName = "username" passwordParamName = "password" validate { credentials -> if (credentials.name == "jetbrains" && credentials.password == "foobar") { UserIdPrincipal(credentials.name) } else { null } } challenge { call.respond(HttpStatusCode.Unauthorized, "Credentials are not valid") } } }

Step 2: Protect specific resources

After configuring the form provider, you need to define a post route where the data gets sent. Then, add this route inside the authenticate function. In the case of successful authentication, you can retrieve an authenticated UserIdPrincipal inside a route handler using the call.principal function and get a name of an authenticated user.

routing { authenticate("auth-form") { post("/login") { call.respondText("Hello, ${call.principal<UserIdPrincipal>()?.name}!") } } }

You can use Session authentication to store a logged-in user's ID. For example, when a user logs in using a web form for the first time, you can save a username to a cookie session and authorize this user on subsequent requests using the session provider.

Last modified: 02 April 2024