Skip to content

Commit 748b872

Browse files
authored
Allow for jwtAuth being provided inside of F[_] (#364)
This allows for the keys being stored in a database or fetched from an api.
1 parent 7dc095d commit 748b872

File tree

2 files changed

+35
-9
lines changed

2 files changed

+35
-9
lines changed

core/src/main/scala/dev/profunktor/auth/middleware.scala

+14-7
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ object JwtAuthMiddleware {
1414
def apply[F[_]: MonadThrow, A](
1515
jwtAuth: JwtAuth,
1616
authenticate: JwtToken => JwtClaim => F[Option[A]]
17+
): AuthMiddleware[F, A] =
18+
apply(jwtAuth.pure, authenticate)
19+
20+
def apply[F[_]: MonadThrow, A](
21+
jwtAuth: F[JwtAuth],
22+
authenticate: JwtToken => JwtClaim => F[Option[A]]
1723
): AuthMiddleware[F, A] = {
1824
val dsl = new Http4sDsl[F] {}; import dsl.*
1925

@@ -23,15 +29,16 @@ object JwtAuthMiddleware {
2329
val authUser: Kleisli[F, Request[F], Either[String, A]] =
2430
Kleisli { request =>
2531
AuthHeaders.getBearerToken(request).fold("Bearer token not found".asLeft[A].pure[F]) { token =>
26-
jwtDecode[F](token, jwtAuth)
27-
.flatMap(authenticate(token))
28-
.map(_.fold("not found".asLeft[A])(_.asRight[String]))
29-
.recover {
30-
case _: JwtException => "Invalid access token".asLeft[A]
31-
}
32+
jwtAuth.flatMap(auth =>
33+
jwtDecode[F](token, auth)
34+
.flatMap(authenticate(token))
35+
.map(_.fold("not found".asLeft[A])(_.asRight[String]))
36+
.recover {
37+
case _: JwtException => "Invalid access token".asLeft[A]
38+
}
39+
)
3240
}
3341
}
34-
3542
AuthMiddleware(authUser, onFailure)
3643
}
3744
}

core/src/test/scala/dev/profunktor/auth/JwtAuthMiddlewareSuite.scala

+21-2
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
package dev.profunktor.auth
22

33
import scala.util.Try
4-
54
import cats.data.OptionT
65
import cats.effect.IO
76
import cats.effect.unsafe.implicits.global
87
import cats.syntax.all.*
9-
108
import munit.FunSuite
119
import org.http4s.*
1210

11+
import scala.util.control.NoStackTrace
12+
1313
class JwtAuthMiddlewareSpec extends FunSuite with JwtFixture {
1414

1515
private def assertResp(response: OptionT[IO, Response[IO]], expected: Status) =
@@ -41,6 +41,25 @@ class JwtAuthMiddlewareSpec extends FunSuite with JwtFixture {
4141
assertResp(middleware(adminRoute).run(noUserAdminReq), Status.Forbidden)
4242
}
4343

44+
test("Admin Route gives 200 when there's a valid token and secret is fetched via F[_]") {
45+
val middleware = JwtAuthMiddleware[IO, AuthUser](IO.pure(jwtAuth), authenticate)
46+
assertResp(middleware(adminRoute).run(goodAdminReq), Status.Ok)
47+
}
48+
49+
test("Admin Route fails when secret fetching via F[_] fails") {
50+
val exception = new Exception("key fetching failed") with NoStackTrace
51+
val middleware = JwtAuthMiddleware[IO, AuthUser](
52+
IO.raiseError(exception),
53+
authenticate
54+
)
55+
middleware(adminRoute)
56+
.run(goodAdminReq)
57+
.value
58+
.attempt
59+
.map(response => assertEquals(response, Left(exception)))
60+
.unsafeToFuture()
61+
}
62+
4463
}
4564

4665
object TestUsers {}

0 commit comments

Comments
 (0)