Form-based authentication in Ktor Server
Edit pageLast modified: 06 February 2025Required dependencies: io.ktor:ktor-server-auth
Code examples: auth-form-html-dsl, auth-form-session
Native server support: ✅
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.
tip
Given that username and password are passed as a clear text when using form-based authentication, you need to use HTTPS/TLS to protect sensitive information.
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:
An unauthenticated client makes a request to a specific route in a server application.
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.
tip
Ktor allows you to build a form using Kotlin DSL, or you can choose between various JVM template engines, such as FreeMarker, Velocity, and so on.
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.
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
andpasswordParamName
properties specify parameter names used to fetch a username and password.The
validate
function validates a username and password. Thevalidate
function checksUserPasswordCredential
and returns aUserIdPrincipal
in the case of successful authentication ornull
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")
}
}
}
tip
As for the
basic
authentication, you can also use UserHashedTableAuth to validate users stored in an in-memory table that keeps usernames and password hashes.
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.