0

I have unauthenticated routes and authenticated routes in my Akka/Spray DSL. Below is simplified version of the code

val nakedRoutes = pathPrefix("user") {
  post {
    entity(as[UserNew]) { user =>
      (validate(EmailValidator.getInstance().isValid(user.email), s"Invalid email address ${user.email}") & validate(!user.password.isEmpty, "Password should not be empty")) {
          complete {
            UserWire(new ObjectId(), user.firstName, user.lastName, user.email, user.company, user.role, new ObjectId())
            }
        }
    }
  }
}

val myAuthorization: Directive[Tuple1[String]] = (headerValueByName("X-API-Token") | parameter("token")).tflatMap[Tuple1[String]]{
    case Tuple1(token) => if (!token.isEmpty) provide(token.reverse) else complete(StatusCodes.Forbidden -> "API token is not provided")
  }

val authenticatedRoutes = myAuthorization { user =>
  get { complete { "" } }
}

val routes = (decodeRequest & encodeResponse) {
    authenticatedRoutes ~ nakedRoutes
  }

The idea is that user makes POST /user request, gets token and uses it for authenticated routes.

The problem I have is that when validation of email fails I get incorrect rejection

Request is missing required HTTP header 'X-API-Token'

Why doesn't it throw last occurred rejection ? How does it pick what rejection to return to the client ?

I can probably validate email manually with if-else and return custom complete{} but I'm not sure it's right approach with akka-http.

expert
  • 29,290
  • 30
  • 110
  • 214

1 Answers1

0

Well, changing myAuthorization to following code helped but I don't understand why :) If @roland-kuhn or @jrudolph can comment on this I'd greatly appreciate it.

If I refer to old Spray's doc I'd expect rejections generated by myAuthorization to be canceled because post directive allowed the request to pass.

val myAuthorization: Directive[Tuple1[String]] = (headerValueByName("X-API-Token") | parameter("token")).tflatMap[Tuple1[String]]{
  case Tuple1(token) => if (!token.isEmpty) provide(token.reverse) else complete(StatusCodes.Forbidden -> "API token is invalid")
}.recover {
  case rejections => reject(ValidationRejection("API token is not provided"))
}
expert
  • 29,290
  • 30
  • 110
  • 214