Authentication Example
Authentication Server Example
zio-http-example/src/main/scala/example/AuthenticationServer.scala
package example
import java.time.Clock
import zio._
import zio.http.Middleware.bearerAuth
import zio.http._
import zio.http.codec.PathCodec.string
import pdi.jwt.{Jwt, JwtAlgorithm, JwtClaim}
object AuthenticationServer extends ZIOAppDefault {
/**
* This is an example to demonstrate barer Authentication middleware. The
* Server has 2 routes. The first one is for login,Upon a successful login, it
* will return a jwt token for accessing protected routes. The second route is
* a protected route that is accessible only if the request has a valid jwt
* token. AuthenticationClient example can be used to makes requests to this
* server.
*/
// Secret Authentication key
val SECRET_KEY = "secretKey"
implicit val clock: Clock = Clock.systemUTC
// Helper to encode the JWT token
def jwtEncode(username: String): String = {
val json = s"""{"user": "${username}"}"""
val claim = JwtClaim {
json
}.issuedNow.expiresIn(300)
Jwt.encode(claim, SECRET_KEY, JwtAlgorithm.HS512)
}
// Helper to decode the JWT token
def jwtDecode(token: String): Option[JwtClaim] = {
Jwt.decode(token, SECRET_KEY, Seq(JwtAlgorithm.HS512)).toOption
}
// Http app that is accessible only via a jwt token
def user: HttpApp[Any] = Routes(
Method.GET / "user" / string("name") / "greet" -> handler { (name: String, _: Request) =>
Response.text(s"Welcome to the ZIO party! ${name}")
},
).toHttpApp @@ bearerAuth(jwtDecode(_).isDefined)
// App that let's the user login
// Login is successful only if the password is the reverse of the username
def login: HttpApp[Any] =
Routes(
Method.GET / "login" / string("username") / string("password") ->
handler { (username: String, password: String, _: Request) =>
if (password.reverse.hashCode == username.hashCode) Response.text(jwtEncode(username))
else Response.text("Invalid username or password.").status(Status.Unauthorized)
},
).toHttpApp
// Composing all the HttpApps together
val app: HttpApp[Any] = login ++ user
// Run it like any simple app
override val run = Server.serve(app).provide(Server.default)
}
Authentication Client Example
zio-http-example/src/main/scala/example/AuthenticationClient.scala
package example
import zio._
import zio.http._
object AuthenticationClient extends ZIOAppDefault {
/**
* This example is trying to access a protected route in AuthenticationServer
* by first making a login request to obtain a jwt token and use it to access
* a protected route. Run AuthenticationServer before running this example.
*/
val url = "http://localhost:8090"
val loginUrl = URL.decode(s"${url}/login/username/emanresu").toOption.get
val greetUrl = URL.decode(s"${url}/user/userName/greet").toOption.get
val program = for {
client <- ZIO.service[Client]
// Making a login request to obtain the jwt token. In this example the password should be the reverse string of username.
token <- client(Request.get(loginUrl)).flatMap(_.body.asString)
// Once the jwt token is procured, adding it as a Bearer token in Authorization header while accessing a protected route.
response <- client(Request.get(greetUrl).addHeader(Header.Authorization.Bearer(token)))
body <- response.body.asString
_ <- Console.printLine(body)
} yield ()
override val run = program.provide(Client.default, Scope.default)
}
Middleware Basic Authentication Example
zio-http-example/src/main/scala/example/BasicAuth.scala
package example
import zio._
import zio.http.Middleware.basicAuth
import zio.http._
import zio.http.codec.PathCodec.string
object BasicAuth extends ZIOAppDefault {
// Http app that requires a JWT claim
val user: HttpApp[Any] = Routes(
Method.GET / "user" / string("name") / "greet" ->
handler { (name: String, _: Request) =>
Response.text(s"Welcome to the ZIO party! ${name}")
},
).toHttpApp
// Composing all the HttpApps together
val app: HttpApp[Any] = user @@ basicAuth("admin", "admin")
// Run it like any simple app
val run = Server.serve(app).provide(Server.default)
}