0

I've following code in http4s 0.8.6 and I'm trying to upgrade it to http4s 0.16.6.

package clear.service

import clear.api.intf.Scope
import clear.api.impl._
import clear.dao.AbstractTokenFactory

import org.http4s._
import org.http4s.server._
import org.http4s.dsl._
import org.http4s.headers.Authorization

import concurrent.ExecutionContext

case class Authorized(
      sessionCache: AbstractSessionCache,
      tokenFactory: AbstractTokenFactory,
      wrappedService: Map[Scope,ClearSession => HttpService]) {

  def unauth(info: Map[String,String]) = Unauthorized(Challenge("Bearer", "/", info))

  val UNAUTHORIZED    = unauth(Map())
  val INVALID_TOKEN   = unauth(Map("error" -> "invalid_token"))
  val INVALID_SESSION = unauth(Map("error" -> "invalid_session"))

  // Authentication protocol
  // See http://self-issued.info/docs/draft-ietf-oauth-v2-bearer.html

  def service(implicit executionContext: ExecutionContext) =
    HttpService(PartialFunction( req =>
      req.headers.get(Authorization).map {
        case Authorization(OAuth2BearerToken(t)) =>
          tokenFactory.validate(t).fold(INVALID_TOKEN)( jwt =>
            wrappedService.get(jwt.scope).fold(UNAUTHORIZED /* No services in scope */ )( svc =>
              sessionCache.get(jwt).fold(INVALID_SESSION)( session =>
                svc(session).or(req, NotFound())
              )
            )
          )
        case _ => UNAUTHORIZED  // Authorization header without bearer token
      }.getOrElse(UNAUTHORIZED) // Missing Authorization header
    ) )

}

Above code works well.

When refactoring the code for http4s support, I'm getting error. Not sure if I'm doing it in correct way.

package clear.service

import clear.api.impl._
import clear.api.intf.Scope
import clear.dao.AbstractTokenFactory
import org.http4s._
import org.http4s.dsl._
import org.http4s.headers.Authorization
import scalaz.Scalaz.ToOptionOpsFromOption
import scalaz.Kleisli
import scalaz.concurrent.Task

case class Authorized(
                         sessionCache: AbstractSessionCache,
                         tokenFactory: AbstractTokenFactory,
                         wrappedService: Map[Scope, ClearSession => HttpService]) {
    def unauth(info: Map[String,String]) = Unauthorized(Challenge("Bearer", "/", info))
    
    val UNAUTHORIZED = unauth(Map())
    val INVALID_TOKEN = unauth(Map("error" -> "invalid_token"))
    val INVALID_SESSION = unauth(Map("error" -> "invalid_session"))
    
    val service: Service[Request, Task[MaybeResponse]] = Kleisli({ request =>
        (for {
            header <- request.headers.get(Authorization).toRightDisjunction(UNAUTHORIZED)
            token <- tokenFactory.validate(header.value).toRightDisjunction(INVALID_TOKEN)
            svc <- wrappedService.get(token.scope).toRightDisjunction(UNAUTHORIZED)
            session <- sessionCache.get(token).toRightDisjunction(INVALID_SESSION)
        } yield (svc, session)).map(e => e._1(e._2).apply(request).or(NotFound()))
    })
}

Error:

[error] /Service.scala:65:5: type mismatch;
[error]  found   : org.http4s.Service[org.http4s.Request,scalaz.concurrent.Task[org.http4s.MaybeResponse]]
[error]     (which expands to)  scalaz.Kleisli[scalaz.concurrent.Task,org.http4s.Request,scalaz.concurrent.Task[org.http4s.MaybeResponse]]
[error]  required: org.http4s.Service[org.http4s.Request,org.http4s.MaybeResponse]
[error]     (which expands to)  scalaz.Kleisli[scalaz.concurrent.Task,org.http4s.Request,org.http4s.MaybeResponse]
[error]                 ).service
[error]                   ^

Any suggestions for the fix? I've tried to get idea from https://http4s.org/v0.16/auth/ but I'm not able to resolve.

Sujit Baniya
  • 895
  • 9
  • 27

0 Answers0