import pdi.jwt.{Jwt, JwtAlgorithm, JwtClaim}
import zio.http._
import zio.http.Server
import zio._
import java.time.Clock
object Authentication extends App {
val SECRET_KEY = "secretKey"
implicit val clock: Clock = Clock.systemUTC
def jwtEncode(username: String): String = {
val json = s"""{"user": "${username}"}"""
val claim = JwtClaim { json }.issuedNow.expiresIn(60)
Jwt.encode(claim, SECRET_KEY, JwtAlgorithm.HS512)
}
def jwtDecode(token: String): Option[JwtClaim] = {
Jwt.decode(token, SECRET_KEY, Seq(JwtAlgorithm.HS512)).toOption
}
def authenticate[R, E](fail: HttpApp[R, E], success: JwtClaim => HttpApp[R, E]): HttpApp[R, E] =
Http
.fromFunction[Request] {
_.getHeader("X-ACCESS-TOKEN")
.flatMap(header => jwtDecode(header._2.toString))
.fold[HttpApp[R, E]](fail)(success)
}
.flatten
def user(claim: JwtClaim): UHttpApp = Http.collect[Request] {
case Method.GET -> !! / "user" / name / "greet" => Response.text(s"Welcome to the ZIO party! ${name}")
case Method.GET -> !! / "user" / "expiration" => Response.text(s"Expires in: ${claim.expiration.getOrElse(-1L)}")
}
def login: UHttpApp = Http.collect[Request] { case Method.GET -> !! / "login" / username / password =>
if (password.reverse == username) Response.text(jwtEncode(username))
else Response.fromHttpError(HttpError.Unauthorized("Invalid username of password\n"))
}
val app: UHttpApp = login ++ authenticate(Http.forbidden("Not allowed!"), user)
override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] =
Server.start(8090, app).exitCode
}