
kotlin-server.libraries.ktor.ApiKeyAuth.kt.mustache Maven / Gradle / Ivy
package {{packageName}}.infrastructure
import io.ktor.application.ApplicationCall
import io.ktor.application.call
import io.ktor.auth.*
import io.ktor.http.auth.*
import io.ktor.request.ApplicationRequest
import io.ktor.response.respond
enum class ApiKeyLocation(val location: String) {
QUERY("query"),
HEADER("header")
}
data class ApiKeyCredential(val value: String): Credential
data class ApiPrincipal(val apiKeyCredential: ApiKeyCredential?) : Principal
/**
* Represents a Api Key authentication provider
* @param name is the name of the provider, or `null` for a default provider
*/
class ApiKeyAuthenticationProvider(name: String?) : AuthenticationProvider(name) {
internal var authenticationFunction: suspend ApplicationCall.(ApiKeyCredential) -> Principal? = { null }
var apiKeyName: String = "";
var apiKeyLocation: ApiKeyLocation = ApiKeyLocation.QUERY;
/**
* Sets a validation function that will check given [ApiKeyCredential] instance and return [Principal],
* or null if credential does not correspond to an authenticated principal
*/
fun validate(body: suspend ApplicationCall.(ApiKeyCredential) -> Principal?) {
authenticationFunction = body
}
}
fun Authentication.Configuration.apiKeyAuth(name: String? = null, configure: ApiKeyAuthenticationProvider.() -> Unit) {
val provider = ApiKeyAuthenticationProvider(name).apply(configure)
val apiKeyName = provider.apiKeyName
val apiKeyLocation = provider.apiKeyLocation
val authenticate = provider.authenticationFunction
provider.pipeline.intercept(AuthenticationPipeline.RequestAuthentication) { context ->
val credentials = call.request.apiKeyAuthenticationCredentials(apiKeyName, apiKeyLocation)
val principal = credentials?.let { authenticate(call, it) }
val cause = when {
credentials == null -> AuthenticationFailedCause.NoCredentials
principal == null -> AuthenticationFailedCause.InvalidCredentials
else -> null
}
if (cause != null) {
context.challenge(apiKeyName, cause) {
// TODO: Verify correct response structure here.
call.respond(UnauthorizedResponse(HttpAuthHeader.Parameterized("API_KEY", mapOf("key" to apiKeyName), HeaderValueEncoding.QUOTED_ALWAYS)))
it.complete()
}
}
if (principal != null) {
context.principal(principal)
}
}
}
fun ApplicationRequest.apiKeyAuthenticationCredentials(apiKeyName: String, apiKeyLocation: ApiKeyLocation): ApiKeyCredential? {
val value: String? = when(apiKeyLocation) {
ApiKeyLocation.QUERY -> this.queryParameters[apiKeyName]
ApiKeyLocation.HEADER -> this.headers[apiKeyName]
}
when (value) {
null -> return null
else -> return ApiKeyCredential(value)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy