CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-ktor--ktor-server-auth-jvm

Authentication and authorization plugin for Ktor server applications

Pending
Overview
Eval results
Files

basic-auth.mddocs/

Basic Authentication

HTTP Basic authentication implementation that validates username and password credentials sent in the Authorization header. This provider extracts credentials from the HTTP Basic authentication scheme and validates them using a custom authentication function.

Configuration

fun AuthenticationConfig.basic(
    name: String? = null,
    configure: BasicAuthenticationProvider.Config.() -> Unit
)

@KtorDsl
class BasicAuthenticationProvider.Config(name: String?) : AuthenticationProvider.Config(name) {
    var realm: String
    var charset: Charset?
    fun validate(body: suspend ApplicationCall.(UserPasswordCredential) -> Any?)
    fun challenge(body: ChallengeFunction)
    fun skipWhen(predicate: ApplicationCallPredicate)
}

Configuration Properties

  • realm: The authentication realm displayed to users (default: "Ktor Server")
  • charset: Character encoding for credential parsing (default: UTF-8)

Configuration Functions

  • validate: Suspend function that validates credentials and returns a principal
  • challenge: Custom challenge function for authentication failures
  • skipWhen: Predicate to skip authentication for certain calls

Basic Usage

install(Authentication) {
    basic("auth-basic") {
        realm = "Access to protected resources"
        validate { credentials ->
            if (credentials.name == "admin" && credentials.password == "secret") {
                UserIdPrincipal(credentials.name)
            } else {
                null
            }
        }
    }
}

routing {
    authenticate("auth-basic") {
        get("/admin") {
            val principal = call.principal<UserIdPrincipal>()
            call.respond("Welcome ${principal?.name}!")
        }
    }
}

Advanced Configuration

Custom Challenge Response

basic("auth-basic") {
    realm = "Secure Area"
    validate { credentials ->
        // Validate against database
        userService.authenticate(credentials)
    }
    challenge { defaultScheme, realm ->
        call.respond(
            UnauthorizedResponse(
                HttpAuthHeader.basicAuthChallenge(realm)
            )
        )
    }
}

Using Hashed Password Table

val hashedUserTable = UserHashedTableAuth(
    table = mapOf(
        "admin" to decodeBase64("password_hash"),
        "user" to decodeBase64("another_hash")
    ),
    digester = getDigestFunction("SHA-256") { "ktor${it.length}" }
)

basic("auth-basic") {
    realm = "Protected Area"
    validate { credentials ->
        hashedUserTable.authenticate(credentials)
    }
}

API Reference

Provider Class

class BasicAuthenticationProvider internal constructor(
    config: Config
) : AuthenticationProvider(config)

abstract class AuthenticationProvider(config: Config) {
    abstract suspend fun onAuthenticate(context: AuthenticationContext)
    
    open class Config(val name: String?) {
        fun skipWhen(predicate: ApplicationCallPredicate)
    }
}

Credential Extraction

fun ApplicationRequest.basicAuthenticationCredentials(charset: Charset? = null): UserPasswordCredential?

Authentication Function Type

typealias AuthenticationFunction<C> = suspend ApplicationCall.(C) -> Any?

Challenge Function Type

typealias ChallengeFunction = suspend PipelineContext<*, ApplicationCall>.(
    defaultScheme: String,
    realm: String
) -> Unit

Common Integration Patterns

Database Integration

basic("database-auth") {
    realm = "Database Protected"
    validate { credentials ->
        transaction {
            Users.select { Users.username eq credentials.name }
                .singleOrNull()
                ?.let { user ->
                    if (BCrypt.checkpw(credentials.password, user[Users.passwordHash])) {
                        UserIdPrincipal(credentials.name)
                    } else null
                }
        }
    }
}

Multiple Authentication Schemes

// Allow both basic and bearer authentication
authenticate("auth-basic", "auth-bearer", strategy = AuthenticationStrategy.FirstSuccessful) {
    get("/api/data") {
        // Handle authenticated request
    }
}

Error Handling

Basic authentication failures are handled through the challenge system:

sealed class AuthenticationFailedCause {
    object NoCredentials : AuthenticationFailedCause()
    object InvalidCredentials : AuthenticationFailedCause()
    class Error(val message: String) : AuthenticationFailedCause()
}

The provider automatically returns appropriate HTTP status codes:

  • 401 Unauthorized: When credentials are invalid or missing
  • 403 Forbidden: When authentication succeeds but authorization fails

Security Considerations

  • Basic authentication transmits credentials in Base64 encoding (not encryption)
  • Always use HTTPS in production to protect credentials in transit
  • Consider rate limiting to prevent brute force attacks
  • Store passwords using secure hashing algorithms (bcrypt, scrypt, etc.)
  • Validate input to prevent injection attacks

Install with Tessl CLI

npx tessl i tessl/maven-io-ktor--ktor-server-auth-jvm

docs

basic-auth.md

bearer-auth.md

form-session-auth.md

index.md

jvm-features.md

oauth.md

tile.json