scalaakkaakka-http

Akka HTTP Scala JWT Authentication Error 'None of the overloaded alternatives of method decode'


I'm trying to add a JWT authentication to my Akka HTTP Scala application API.

I'm using the maven dependency modules jwt-circe and jwt-core from the maven repository.

However the current code is giving me the Type errors:

case Some(jwtToken) if Jwt.isValid(jwtToken, secretKey, Seq(JwtAlgorithm.HS256))

Type Error: None of the overloaded alternatives of method isValid in trait JwtCore with types.

onComplete(Jwt.decode(jwtToken, secretKey, Seq(JwtAlgorithm.HS256)))

Type Error: None of the overloaded alternatives of method decode in trait JwtCore with types.

Again, I installed both the dependency modules jwt-circe and jwt-core (check the sbt code).

Could you please help me identify the issue?

Thanks in advance!

My current code looks like below:

case classes:


final case class Account(name: String, age: Int, country: String, roles: List[String])

object JsonFormats {
import DefaultJsonProtocol._

implicit val accountFormat: RootJsonFormat[Account] = jsonFormat4(Account.apply)

The JWT Code:


import pdi.jwt.{ Jwt, JwtAlgorithm, JwtClaim, JwtCirce }

private val expiresIn = 1 * 24 * 60 * 60
implicit val clock: Clock = Clock.systemUTC
private val secretKey = "vp-akka-http-jwt"

def authenticated: Directive1[Account] =
  optionalHeaderValueByName("Authorization").flatMap {
    case Some(jwtToken) if Jwt.isValid(jwtToken, secretKey, Seq(JwtAlgorithm.HS256)) =>
         getClaims(jwtToken) match {
           case Some(account) => provide(account)
           case None => reject(AuthorizationFailedRejection).toDirective[Tuple1[Account]]
         }
    case t => println(t.get)
           complete(StatusCodes.Unauthorized)
}
      
private def getClaims(jwtToken: String): Option[Account] = {
    onComplete(Jwt.decode(jwtToken, secretKey, Seq(JwtAlgorithm.HS256))){
       case Success(value) => 
            Some(value.content.parseJson.convertTo[Account])
       case Failure(ex) => None
    }            
}

The SBT config:


lazy val akkaHttpVersion = "10.6.3"
lazy val akkaVersion    = "2.9.4"

resolvers += "Akka library repository".at("https://repo.akka.io/maven")

fork := true

lazy val root = (project in file(".")).
  settings(
    inThisBuild(List(
      organization    := "com.example",
      scalaVersion    := "3.3.3"
    )),
    name := "eskimi-bidding-agent",
    libraryDependencies ++= Seq(
      // ....
      ("com.github.jwt-scala"     %% "jwt-circe"             % "10.0.1")
         .exclude("io.circe", "circe-parser_3")
         .exclude("io.circe", "circe-core_3")
         .exclude("org.typelevel", "cats-kernel_3")
         .exclude("org.typelevel", "cats-core_3")
         .exclude("io.circe", "circe-numbers_3")
         .exclude("org.typelevel", "jawn-parser_3")
         .exclude("io.circe", "circe-jawn_3"),
      "com.github.jwt-scala"     %% "jwt-core"             % "10.0.1",
      // ....
    )
  )


The full code error:

This is the Jwt.isValid error. It is very similar to the Jwt.decode error.

Type Error:
case Some(jwtToken) if Jwt.isValid(jwtToken, secretKey, Seq(JwtAlgorithm.HS256)) 
None of the overloaded alternatives of method isValid in trait JwtCore with types

(token: String, key: java.security.PublicKey): Boolean
(token: String, key: java.security.PublicKey, options: pdi.jwt.JwtOptions): Boolean
(token: String, key: java.security.PublicKey, algorithms: Seq[pdi.jwt.algorithms.JwtAsymmetricAlgorithm]): Boolean
(token: String, key: java.security.PublicKey, algorithms: Seq[pdi.jwt.algorithms.JwtAsymmetricAlgorithm], options: pdi.jwt.JwtOptions): Boolean
(token: String, key: javax.crypto.SecretKey): Boolean
(token: String, key: javax.crypto.SecretKey, options: pdi.jwt.JwtOptions): Boolean
(token: String, key: javax.crypto.SecretKey, algorithms: Seq[pdi.jwt.algorithms.JwtHmacAlgorithm]): Boolean
(token: String, key: javax.crypto.SecretKey, algorithms: Seq[pdi.jwt.algorithms.JwtHmacAlgorithm], options: pdi.jwt.JwtOptions): Boolean
(token: String, key: String, algorithms: => Seq[pdi.jwt.algorithms.JwtAsymmetricAlgorithm]): Boolean
(token: String, key: String, algorithms: => Seq[pdi.jwt.algorithms.JwtAsymmetricAlgorithm], options: pdi.jwt.JwtOptions): Boolean
(token: String, key: String, algorithms: Seq[pdi.jwt.algorithms.JwtHmacAlgorithm]): Boolean
(token: String, key: String, algorithms: Seq[pdi.jwt.algorithms.JwtHmacAlgorithm], options: pdi.jwt.JwtOptions): Boolean
(token: String): Boolean
(token: String, options: pdi.jwt.JwtOptions): Boolean 
match arguments ((jwtToken : String), (com.example.WebServer.secretKey : String), scala.collection.Seq[pdi.jwt.JwtAlgorithm.HS256.type])


Solution

  • It sounds like the library is expecting scala.collection.immutable.Seq and you're providing scala.collection.Seq. Or maybe the library accepts scala.collection.Seq but you're having Seq as an alias of a totally different type?

    You can use scala.collection.immutable.Seq explicitly and/or check your imports statements.


    You can read more about the 3 different scala.collection packages (root, immutable, mutable) at https://docs.scala-lang.org/overviews/collections-2.13/overview.html. :

    A collection in package scala.collection.immutable is guaranteed to be immutable for everyone. (...)

    A collection in package scala.collection.mutable is known to have some operations that change the collection in place. (...)

    A collection in package scala.collection can be either mutable or immutable. (...) Generally, the root collections in package scala.collection support transformation operations affecting the whole collection, the immutable collections in package scala.collection.immutable typically add operations for adding or removing single values, and the mutable collections in package scala.collection.mutable typically add some side-effecting modification operations to the root interface.

    Another difference between root collections and immutable collections is that clients of an immutable collection have a guarantee that nobody can mutate the collection, whereas clients of a root collection only promise not to change the collection themselves. Even though the static type of such a collection provides no operations for modifying the collection, it might still be possible that the run-time type is a mutable collection which can be changed by other clients.

    By default, Scala always picks immutable collections.