Kotlin Academy · Lesson

Authentication Plugins: JWT and Session

Secure Ktor routes using JWT bearer tokens and session-based authentication.

Lesson 4 of 413 steps

Authentication Plugins: JWT and Session is a free Kotlin Academy lesson on CoddyKit. This is lesson 4 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the Kotlin Academy learning path, and your progress syncs across the web and the CoddyKit app. The Kotlin Academy course includes 4 lessons in total.

Ktor Authentication Overview

Ktor's Authentication plugin provides a unified API for protecting routes. You configure one or more providers (JWT, Session, Basic, OAuth, etc.) and then wrap routes in an authenticate("providerName") { } block.

Adding Auth Dependencies

Add the auth and JWT libraries to your build:

dependencies {
    implementation("io.ktor:ktor-server-auth:2.3.12")
    implementation("io.ktor:ktor-server-auth-jwt:2.3.12")
    implementation("io.ktor:ktor-server-sessions:2.3.12")
}

Configuring JWT Authentication

Install the Authentication plugin and configure a JWT provider. The verifier validates the token signature; validate extracts the principal from the payload:

install(Authentication) {
    jwt("auth-jwt") {
        realm = "ktor app"
        verifier(
            JWT.require(Algorithm.HMAC256(secret))
                .withAudience(audience)
                .withIssuer(issuer)
                .build()
        )
        validate { credential ->
            if (credential.payload.getClaim("username").asString() != null)
                JWTPrincipal(credential.payload)
            else null
        }
    }
}

Protecting Routes with JWT

Wrap any route group in authenticate("auth-jwt") { }. Unauthenticated requests receive a 401 automatically:

routing {
    authenticate("auth-jwt") {
        get("/protected") {
            val principal = call.principal<JWTPrincipal>()!!
            val username = principal.payload.getClaim("username").asString()
            call.respondText("Hello, $username")
        }
    }
}

Issuing a JWT Token

Generate and sign a JWT on the login endpoint using the java-jwt library:

post("/login") {
    val user = call.receive<LoginRequest>()
    // validate credentials ...
    val token = JWT.create()
        .withAudience(audience)
        .withIssuer(issuer)
        .withClaim("username", user.username)
        .withExpiresAt(Date(System.currentTimeMillis() + 3_600_000))
        .sign(Algorithm.HMAC256(secret))
    call.respond(mapOf("token" to token))
}

Session Authentication

Sessions store user state server-side (or client-side as signed cookies). Install the Sessions plugin and define a session data class:

data class UserSession(val userId: Long, val username: String)

install(Sessions) {
    cookie<UserSession>("user_session") {
        cookie.path = "/"
        cookie.httpOnly = true
    }
}

Configuring Session Auth Provider

Create a session authentication provider that reads the session and returns a principal:

install(Authentication) {
    session<UserSession>("auth-session") {
        validate { session -> session }
        challenge { call.respond(HttpStatusCode.Unauthorized) }
    }
}

Setting and Clearing Sessions

Set a session after login with call.sessions.set() and clear it on logout with call.sessions.clear():

post("/login") {
    val creds = call.receive<LoginRequest>()
    // validate ...
    call.sessions.set(UserSession(userId = 1L, username = creds.username))
    call.respond(HttpStatusCode.OK)
}

post("/logout") {
    call.sessions.clear<UserSession>()
    call.respond(HttpStatusCode.OK)
}

JWT vs Session: When to Use Each

JWT: stateless, good for APIs consumed by mobile/SPA clients. Token carries all claims; server needs no session store. Sessions: stateful, good for server-rendered web apps. Session ID in cookie; server holds the data (memory, Redis, DB).

Combining Multiple Auth Providers

You can define multiple providers and require any of them using authenticate("jwt", "session") { }. Ktor tries each in order and accepts the request if any provider validates successfully.

Custom Challenge Responses

Each provider has a challenge block that defines what to do when authentication fails. Return a 401 with a JSON error body instead of the default WWW-Authenticate header:

jwt("auth-jwt") {
    // ...
    challenge { _, _ ->
        call.respond(HttpStatusCode.Unauthorized, mapOf("error" to "Token expired or invalid"))
    }
}

Quick Check

What does the validate block in a Ktor JWT provider do?

Recap: Authentication Plugins — JWT and Session

Key takeaways:

  • Install Authentication; configure providers (jwt, session, basic, oauth)
  • Protect routes with authenticate("providerName") { }
  • JWT: stateless tokens; sign on login, verify with verifier, read claims in validate
  • Sessions: stateful; call.sessions.set() on login, clear() on logout
  • Use challenge to customize the 401 response format
Free to start

Learn Kotlin with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
51
Lessons
203

Frequently Asked Questions

Is the “Authentication Plugins: JWT and Session” lesson free?

Yes — any 3 lessons of the Kotlin Academy learning path, including “Authentication Plugins: JWT and Session”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The Kotlin Academy course includes 4 lessons in total.

What will I learn in “Authentication Plugins: JWT and Session”?

Secure Ktor routes using JWT bearer tokens and session-based authentication. You practise Kotlin Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Kotlin Academy?

No prior experience is required. Kotlin Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 4 of 4.

How long does the “Authentication Plugins: JWT and Session” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Kotlin Academy lesson?

Yes. Every Kotlin Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Ktor Project Setup: embeddedServer and Application Modules
  2. Routing and Typed Parameters
  3. Content Negotiation and kotlinx.serialization
  4. Authentication Plugins: JWT and Session
← Back to Kotlin Academy