My API clients will pass the session token in the header or query string like:
Http Header with key/value like MyApp-Token abc123
Url:
https://api.example.com/v1/board?authToken=abc123
val secureRoutes =
authenticateToken() { authenticatedContext =>
path("board") {
get {
complete(s"board#index route ${authenticatedContext.user.username}")
}
}
}
Is there a built-in directive that can do this for me or do I have to somehow create my own custom directive that will first look in the HTTP headers, and if not there then look to see if there is a query string value at the key authToken
?
If I have to create a custom directive, any examples I can follow or learn from?
I know I can get a HTTP header using the built-in directive:
headerValueByName("x-authToken") { authToken =>
get {
complete(s"board#index route 2.1 $authToken")
}
}
And there is also a directive to get the value from a query string:
parameter("authToken") { authToken =>
...
}
How could I combine both of them, and then internally I would want to make a database call, and then instead of returning authToken
I want to return a custom case class that will contain data I just loaded from the database like:
case class AuthenticatedContext(authToken: String, user: User, ...)
We can always construct a custom directive or compose the directives as shown below:
case class AuthenticatedContext(authToken: String)
def validateTokenAndGetAuthContext(token: String): Future[AuthenticatedContext] = {
Future.successful(AuthenticatedContext(token))
}
val authToken: Directive1[AuthenticatedContext] = optionalHeaderValueByName("authToken").flatMap {
case Some(token) =>
onComplete(validateTokenAndGetAuthContext(token)).flatMap {
case Failure(_) => reject(AuthorizationFailedRejection)
case Success(value) => provide(value)
}
case None =>
parameter("authToken".optional).flatMap {
case Some(token) =>
onComplete(validateTokenAndGetAuthContext(token)).flatMap {
case Failure(_) => reject(AuthorizationFailedRejection)
case Success(value) => provide(value)
}
case None => reject(AuthorizationFailedRejection)
}
}
It's constructed using HeaderDirectives, ParameterDirectives and FuturesDirectives.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With