Reputation: 191
I have a route in my Ktor application that I want to optionally authenticate. What is the best way to go about this? If I put two routing blocks in, both calls default to the unauthenticated one.
e.g.
routing {
post("/my-route") {
val request = call.receive<MyRouteRequest>()
...
}
authenticate(Constants.myAuthScope) {
post("/my-route") {
val request = call.receive<MyRouteRequest>()
val user = call.principal<User>()
...
}
}
Upvotes: 1
Views: 712
Reputation: 113
Try authenticate
's optional
param, like
authenticate(Constants.myAuthScope, optional = true) {
post("/my-route") {}
}
Upvotes: 1
Reputation: 1482
It should be possible using more explicit models combined with validation of those either in the route or perhaps in the underlying service (depends if this is seen as domain logic or API logic)
For basic auth it looks a bit like:
sealed interface PrincipalResult {
data class User(/* ... */): PrincipalResult
object NoUserProvided: PrincipalResult
// This might be replaced with a null result to conform with the Ktor API
// I prefer making it explicit and communicate what's going on
// and not just accept a null that means everything and nothing.
//
// This can also be made into a data class and expanded
// with additional information, allowing for better errors and richer debugging
object InvalidUserCredentials: PrincipalResult
}
install(Authentication) {
basic("stuart-auth") {
realm = "Access to the '/' path"
validate { credentials ->
if (credentials.isMissing()) {
PrincipalResult.NoUserProvided
} else if (credentials.isValid() {
PrincipalResult.User(/* ... */)
} else {
PrincipalResult.InvalidUserCredentials
}
}
}
}
now one can do:
authenticate(Constants.myAuthScope) {
post("/my-route") {
val request = call.receive<MyRouteRequest>()
val principalResult = call.principal<PrincipalResult>()
when (principalResult) {
is PrincipalResult.User ->
is PrincipalResult.NoUserProvided ->
is PrincipalResult.InvalidUserCredentials ->
}
// ...
}
}
This pattern should of course be applied to whichever authentication scheme you actually use, such as JWT, OAuth, LDAP etc.
Upvotes: 2