lang="en-US"> JWT Authentication with Play Framework - Knoldus Blogs
Knoldus Blogs

JWT Authentication with Play Framework

Reading Time: 3 minutes
In this blog, I will demonstrate how to implement JWT Authentication with Play Framework.

JSON Web Token (JWT) is a compact, self-contained which means securely transfer the information between two parties. It can be sent via Post request or inside the HTTP header. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret or a public/private key pair using RSA It consists three parts separated by the dot(.)  i.e Header, Payload and Signature. The header consists type of the token and hashing algorithm, the payload contains the claims and the claims in a JWT are encoded as a JSON object that is used as the payload or as the plaintext, the signature part is used to verify that the sender of the JWT.

Here, we are using JSON Web Token for authentication with Play Framework, This is a most common way of using JWT. Once the user is logged in, we need to include JWT with each request that allows the user to access the routes, service and resources which authenticate the token in order to permit the request.

Let’s start with the implementation of JWT Authentication using Play Framework:

1. First, we need to include JWT library in our project. There are several libraries for JWT, you can use any of them depending on your requirement, here I am using one of the library i.e.

"com.jason-goodwin" % "authentikat-jwt" % "0.4.5"

2. Next, you need to create JWT utility class in which you need to add all these methods for creating, verifying and decode the JWT token and provide the secret key and algorithm such as HMAC, SHA256.

val JwtSecretKey = "secretKey"
val JwtSecretAlgo = "HS256"

def createToken(payload: String): String = {
  val header = JwtHeader(JwtSecretAlgo)
  val claimsSet = JwtClaimsSet(payload)

  JsonWebToken(header, claimsSet, JwtSecretKey)
}

def isValidToken(jwtToken: String): Boolean =
  JsonWebToken.validate(jwtToken, JwtSecretKey)

def decodePayload(jwtToken: String): Option[String] =
  jwtToken match {
    case JsonWebToken(header, claimsSet, signature) => Option(claimsSet.asJsonString)
    case _                                          => None
  }

3. To implement JWT authentication, we need to create reusable custom secured action by using ActionBulder that authenticates the each subsequent request and verifies the JWT in order to permit the request to access the corresponding service. ActionBulder is the special case of functions that take request as input and thus can build actions and provides several factory methods that help for creating action. To implement ActionBuilder, we need to implement invokeBlock method. So here I have created a custom JWTAuthentication by using ActionBuilder.

case class UserInfo(id: Int,
                    firstName: String,
                    lastName: String,
                    email: String)

case class User(email: String, userId: String)

case class UserRequest[A](userInfo: UserInfo, request: Request[A]) extends WrappedRequest(request)

class SecuredAuthenticator @Inject()(dataSource: DataSource) extends Controller {
  implicit val formatUserDetails = Json.format[User]

  object JWTAuthentication extends ActionBuilder[UserRequest] {
    def invokeBlock[A](request: Request[A], block: (UserRequest[A]) => Future[Result]): Future[Result] = {
      val jwtToken = request.headers.get("jw_token").getOrElse("")

      if (JwtUtility.isValidToken(jwtToken)) {
        JwtUtility.decodePayload(jwtToken).fold {
          Future.successful(Unauthorized("Invalid credential"))
        } { payload =>
          val userCredentials = Json.parse(payload).validate[User].get

          // Replace this block with data source
          val maybeUserInfo = dataSource.getUser(userCredentials.email, userCredentials.userId)

          maybeUserInfo.fold(Future.successful(Unauthorized("Invalid credential")))(userInfo => block(UserRequest(userInfo, request)))
        }
      } else {
        Future.successful(Unauthorized("Invalid credential"))
      }
    }
  }

}

4. Now we can use “JWTAuthentication” the same way we use Action.

  def index = auth.JWTAuthentication { implicit request =>
    Ok(views.html.index(s"Hello ${request.userInfo.firstName} ${request.userInfo.lastName}"))
  }

5.  You can test it through Postman(on which you can send the request and view response),  all we need to do is create a JWT and pass it to the Headers, corresponding to the field “jw_token”. You can create JSON web token by “createToken” method that I have shown you in step 2 by passing payload as a parameter which can be anything, here is the example: 

val payload = """{"email":"test@example.com","userId":"userId123"}"""

JWT looks like this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InRlc3RAZXhhbXBsZS5jb20iLCJ1c2VySWQiOiJ1c2VySWQxMjMifQ.mjMQN8m_wH1NSE9GGexCW_GUh8uruNco18jgt7AWuO4

jwt.png

You can get the source code from here.

I hope this blog is helpful to you!

Thanks 

References:
 

Exit mobile version