avatar

Andres Jaimes

Creating and validating JWT JSON web tokens

By Andres Jaimes

- 2 minutes read - 340 words

This article goes through the process of creating and validating JWT’s (JSON web tokens) using Scala.

Our implementation uses the awesome io.jsonwebtoken library, and can be added to a sbt project like this:

libraryDependencies ++= Seq("io.jsonwebtoken" % "jjwt" % "0.9.1")

Creating a token

We are going to use Scala’s apply/unapply functions for this implementation. This will allow us to use matchers for checking JWT’s.

import java.time.Instant
import java.util.{Date, UUID}

import io.jsonwebtoken.{Claims, Jws, Jwts, SignatureAlgorithm}

import scala.collection.JavaConverters._

object Jwt {

  val Ttl: Int = 3600
  val Secret: String = "MySecret"

  def apply(claims: Map[String, Any]): String = {
    val jwt = Jwts.builder()
      .setId(UUID.randomUUID.toString)
      .setIssuedAt(Date.from(Instant.now()))
      .setExpiration(Date.from(Instant.now().plusSeconds(Ttl)))
      .signWith(SignatureAlgorithm.HS512, Secret.getBytes("UTF-8"))
    
    claims.foreach { case (name, value) =>
      jwt.claim(name, value)
    }
    
    jwt.compact()
  }

Ideally Ttl and Secret should be provided by a configuration object. Such an object can be passed as an implicit parameter to this function.

Use a long secret string. It’s not unusual to have secrets of more than 340 characters.

Validating a token

Add the unapply function.

  def unapply(jwt: String): Option[Map[String, Any]] =
    try {
      val claims: Jws[Claims] = Jwts.parser()
        .setSigningKey(Secret.getBytes("UTF-8"))
        .parseClaimsJws(jwt) // we can trust this JWT
      Option(claims.getBody.asScala.toMap)
    } catch {
      case _: Exception => None
    }

Similar to its apply counterpart, this function may receive an implicit configuration object that holds the Secret string value.

The parseClaimsJws function will throw an exception if the passed token has expired or has been tampered. Therefore, it is safe to read the accompanying claims using:

    Option(claims.getBody.asScala.toMap)

Using our Jwt object

Create a token

val jwt = Jwt(Map(
          "claim1" -> "value1",
          "claim2" -> "value2",
          "claim3" -> "value3"
        ))

Do not forget to encode your token if you are going to use it on urls:

import java.net.URLEncoder
import java.nio.charset.StandardCharsets

URLEncoder.encode(jwt, StandardCharsets.UTF_8.toString)

Validate a token and get the claims.

jwt match {
  case Jwt(claims) =>
    val claim1 = claims("claim1").toString
    val claim2 = claims("claim2").toString
    val claim3 = claims("claim3").toString
    // do something with your claims
  case _ => // Invalid token
}

This implementation offers a flexible and easy way of creating and validating JWT’s.

References