Skip to content

Authentication

An example showing the handling of protected routes.

Authentication.kt
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
package io.github.smiley4.ktoropenapi.examples

import io.github.smiley4.ktoropenapi.OpenApi
import io.github.smiley4.ktoropenapi.config.AuthScheme
import io.github.smiley4.ktoropenapi.config.AuthType
import io.github.smiley4.ktoropenapi.get
import io.github.smiley4.ktoropenapi.openApi
import io.github.smiley4.ktorredoc.redoc
import io.github.smiley4.ktorswaggerui.swaggerUI
import io.ktor.server.application.Application
import io.ktor.server.application.install
import io.ktor.server.auth.Authentication
import io.ktor.server.auth.UserIdPrincipal
import io.ktor.server.auth.authenticate
import io.ktor.server.auth.basic
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty
import io.ktor.server.response.respondText
import io.ktor.server.routing.route
import io.ktor.server.routing.routing

fun main() {
    embeddedServer(Netty, port = 8080, host = "localhost", module = Application::myModule).start(wait = true)
}

private fun Application.myModule() {

    // Install "Authentication" Plugin and setup e.g. Basic-Auth
    // username = "user",  password = "pass"
    install(Authentication) {
        basic {
            realm = "Access to the API"
            validate { credentials ->
                if (credentials.name == "user" && credentials.password == "pass") {
                    UserIdPrincipal(credentials.name)
                } else {
                    null
                }
            }
        }
    }

    // Install and configure the OpenAPI plugin
    install(OpenApi) {
        schemas {  }
        security {
            // configure a basic-auth security scheme
            securityScheme("MySecurityScheme") {
                type = AuthType.HTTP
                scheme = AuthScheme.BASIC
            }
            // if no other security scheme is specified for a route, the one with this name is used instead
            defaultSecuritySchemeNames("MySecurityScheme")
            // if no other response is documented for "401 Unauthorized", this information is used instead
            defaultUnauthorizedResponse {
                description = "Username or password is invalid"
                body<AuthRequired>()
            }
        }
    }

    routing {

        // add the routes for  the api spec, swagger-ui and redoc
        route("swagger") {
            swaggerUI("/api.json")
        }
        route("api.json") {
            openApi()
        }
        route("redoc") {
            redoc("/api.json")
        }

        authenticate {
            // route is in an "authenticate" block -> default security scheme will be used (if not specified otherwise)
            get("protected", {
                // response for "401 Unauthorized" is automatically added if configured in the plugin config and not specified otherwise
            }) {
                call.respondText("Hello World!")
            }

            get("protected2", {
                // response for "401 Unauthorized" is automatically added if configured in the plugin config and not specified otherwise
            }) {
                call.respondText("Hello World!")
            }
        }

        // route is not in an "authenticate" block but "protected" flag is set (e.g. because is it protected by an external reverse-proxy
        // -> specified or default security scheme is used and default "401 Unauthorized" is added if not specified otherwise
        get("externally-protected", {
            // manually specify that this route requires authentication
            protected = true
        }) {
            call.respondText("Hello World!")
        }

        // route is not in an "authenticate" block and "protected" flag is not set
        // -> security schemes will be ignored and not default "401 Unauthorized" response is added
        get("unprotected", {
            securitySchemeNames("MySecurityScheme")
        }) {
            call.respondText("Hello World!")
        }

    }

}


class AuthRequired(val message: String)