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.