scala akka http route with authenticate by a token

2.2k Views Asked by At

i m trying to convert my spray routes in akka http.

It s really complicated for a novice but i almost do everything. I m bloked by the authentication.

Indeed, i have a route with a get param token=???? How can i check this token with akka? My route is :

  val route : Route = {
    path("appActive") {
            get {
                parameters('date_end.as[Long]) {
                    date_end =>
                        onSuccess(requestHandler ? AppActiveGetList(AppActiveRequest(date_end, null, 0))) {
                            case response: Answer =>
                                complete(StatusCodes.OK, response.result)
                            case _ =>
                                complete(StatusCodes.InternalServerError, "Error on the page")
                        }
                }
        }
    }
}

My authenticate function at the moment is (with spray) :

trait TokenValidator {
def validateTokenApp(): ContextAuthenticator[InfoApp] = {
    ctx =>
        val access_token = ctx.request.uri.query.get("access_token")
        if (access_token.isDefined) {
            doAuthApp(access_token.get)
        } else {
            Future(Left(AuthenticationFailedRejection(AuthenticationFailedRejection.CredentialsMissing, List())))
        }
}
}

I didn t find an example i can use easily. Could you help me please?

1

There are 1 best solutions below

3
On BEST ANSWER

Looks like Akka-HTTP authentication directives are stricter in what they expect than Spray's. If you want to keep your doAuthApp unchanged, you'll need to define your own custom directive - along the lines of Akka-HTTP's own authenticateOrRejectWithChallenge.

  def doAuthApp[T](token: String): Future[AuthenticationResult[T]] = ???

  def authenticated[T](authenticator: String => Future[AuthenticationResult[T]]): AuthenticationDirective[T] =
    parameter('access_token.?).flatMap {
      case Some(token) =>
        onSuccess(authenticator(token)).flatMap {
          case Right(s) => provide(s)
          case Left(challenge) =>
            reject(AuthenticationFailedRejection(CredentialsRejected, challenge)): Directive1[T]
        }
      case None =>
        reject(AuthenticationFailedRejection(CredentialsMissing, HttpChallenges.oAuth2("my_realm"))): Directive1[T]
    }

And then wire in the route somewhere like

  val route : Route = {
    path("appActive") {
      (get & authenticated(doAuthApp)){ authResult =>
        parameters('date_end.as[Long]) {
          date_end =>
            ...
        }
      }
    }
  }