Cookie Authentication using Scalatra and JWTs

As part of my work with Arcadia, I've built a Rails application that added a cookie that contains a JWT (pronounced jot). Great! That was fairly simple. Then I had to go over to our Scala application and get it to accept the JWT as identification. Right now, we were keeping it pretty simple and we only care if it's valid. This post will cover what I think is the simplest way to do that, from start to finish. Or you can skip all that and just go look at the full gist.

We want to start off with the JWT parsing. And before we add the code to actually do that, let's add some tests! I decided to use the JWT Scala library and, in particular, jwt-core. It had, in my opinion, the most easy-to-understand documentation so I could indeed RTFM and get my work done. Since I didn't need to add encoding in the actual application (the tokens would be encoded in another application), I added a quick line to encode a token within the tests.

Now that I have my tests, let's add the actual code to decode the JWT! Thanks to JWT Scala, this is pretty simple! The real secret sauce is in this line: userTokenData = parse(decoded).extract[Token].data. That does a lot of heavy lifting! decoded is just a string and parse turns it into this Jvalue object thanks to json4s, but that object is a bit hard to work with. However, I can extract it out to my case class, Token, which is downright magical. If it doesn't include all the fields that I have in Token, it will produce an error. Perfect!

Next I need a reusable Authentication object. This wasn't too bad because I found out that HttpServletRequest has a method called getCookies which... returns the cookies. Excellent. I'm sure this looks weird as an Either, but in this case I really did want Some or None because I didn't care about returning the error to the actual user. I did want to log it though, hence the liberal use of println.

Last, but definitely not least, I need a servlet. Well... tests for the servlet, then the servlet 😛. This is where I actually ran into trouble because I wasn't sure how to pass cookies to the get request in a test. With some help from my boss, we found out that get takes a headers param and you can pass a cookie if it looks like this: headers = Map("Cookie" -> cookie_value). To be honest, it required a bit of trial and error and I'm still trying to figure out exactly what values are being passed.

Screen Shot 2018-05-02 at 11.33.45 AM.png

And finally... my servlet! Short and sweet.

Introduction to Scala

I signed myself up to teach a Scala class through Girl Develop It Pittsburgh a few months ago and the class was supposed to be tomorrow. I say "supposed to" because we only had two people sign up, so we ended up canceling. However, I still made a presentation! And since I spent all that time on a presentation, I decided to make a set of screencasts to accompany that presentation. If you've ever been interested in trying out Scala, I hope this helps. If you need any help or want me to go through some other aspect of Scala, feel free to contact me.

Find the rest of the series here.

Getting Started With Play After Working In Rails

I've now been using Scala since November (so a little over 4 months) and Play since January (exactly two months today). When I first started writing this application, I was brand new to Scala. My boss recommended Scalatra since he had some experience. Since I had none, I agreed and got started. I learn by example, so I first went through and found some projects that I could look at and base my project off. With Rails, this was easy. The Rails Guides are FANTASTIC (I miss them so much). With Scalatra, this was much more challenging. I made some progress, but then I came to a screeching halt, which caused my boss to post to Reddit asking for suggestions. Lemme pull out some of my favorite comments:

On stack overflow there are around ~250 questions tagged with scalatra. There are around 15k play framework related questions. You're pretty much on your own if you go scalatra.
Akka HTTP you pretty much have to have a PhD to understand.
Play lacks a coherent, functional API, documentation for a good 60% of it, and completely lacks the composability and ease of use of alternative frameworks like http4s. Most of these problems with Play are due to poor planning, and being a Lightbend technology which is contorted to work with Akka(and akka-http), yet another poor Lightbend tech. It's a pervasive rot in the community, just like Akka.

GREEEAAAAAAATTTTT. Anyway, we decided to try Play It has documentation (the bar, it is low), at least one book written about it, and some decent templates. I migrated my project over to Play and got going. One of the major differences I noticed between Play and Rails is that Play is not very opinionated. In general, if you look at a Rails project, everything is generally in the same place. Pretty much everyone uses ActiveRecord and the RDMS you choose doesn't really matter. With pretty much any Rails project, you can initialize the database with rake db:create. This is not the case for Play. As far as I can tell, you have to create the database and then Play will run evolutions (migrations). The real problem I have is that there also is no standard. Slick is very popular, but we decided to use the newer kid in class, Quill. And I couldn't find a single example of someone using Play 2.6, Quill, and PostgreSQL. And Play 2.6 is a breaking release from Play 2.5. I found one template that used Play 2.5, Quill, and PostgreSQL, but it broke when I upgraded to Play 2.6. Right now I'm having some database connectivity issues, but I'm hoping to resolve those soon. As soon as I get the app working, I'm going to create a template so hopefully, others won't have as hard of a time as I have.

Overall, I sorta wish I was still working in Rails? I love the simplicity of Ruby and how easy Rails makes it to get a decent CRUD app up and running. It definitely would have only taken me one week to make this app in Rails and it's taken four months (and counting) in Scala.

Option and Either in Scala

I'm used to Ruby. In Ruby, you can use nil with abandon and just do something like if variable to check if it exists. Below is valid Ruby code (though forgive me if I'm now out of practice):

1
2
3
4
5
6
7
def displayUser(user)
  if user
    user.name
  else
    "No name"
  end
end

When I started on this project, I started treating Scala the same way. However, I found out that apparently you want to avoid using null in Scala. My first iteration prior to discovering this was the following:

1
2
3
4
5
6
7
def displayUser(user: User = null): String = {
  if(user != null) {
    return user.name
  } else {
    return "No name"
  }
}

This is not proper Scala. Unlike Ruby, Scala has Option. Option allows you to have Some or None. As you might expect, Some has a value, while None is the equivalent of null. Here's an example of how to do that same function properly:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def displayUser(user: Option[User] = None): String = {
  if(user.isDefined) {
    return user.get.name
  } else {
    return "No name"
  }
}
// call it like this
user = User()
displayUser(Some[user]) //or
displayUser()

Either provides a similar function to Option but is better for returning error messages. The problem I was trying to solve was creating an organization user. For that to happen, there must be an organization and a user. Here's my inital way I did it, thinking as a rubyist:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def validateUserAndOrgExist(email: String, orgId: Long): (Organization, User, Boolean, String) = {
  val user = usersService.findByEmail(email).head
  val organization = organizationsService.find(orgId).head
  if (user == null) {
    return (null, null, false, "User does not exist. Please create user first.")
  } else if (organization == null) {
    return (null, null, false, "Organization does not exist. Please create organization first.")
  } else {
    return (organization, user, true, "both exist")
  }
}

However, the better option (hehe) is to use Either in this case. So here's the better way to do this same function:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
trait ValidationError { val message: String}
case class IdentifierNotFound(message: String) extends ValidationError

def validateUserAndOrgExist(name: String, orgId: Long): Either[IdentifierNotFound, (Organization, User)] = {
  val user = usersService.findByEmail(name).headOption
  val organization = organizationsService.find(orgId).headOption
  if (user.isEmpty) {
    Left(IdentifierNotFound("User does not exist. Please create user first."))
  } else if (organization.isEmpty) {
    Left(IdentifierNotFound("Organization does not exist. Please create organization first."))
  } else {
    Right((organization.get, user.get))
  }
}
// then call it and use it like this:
val validationOfUserOrg = validateUserAndOrgExist("test", 123)
if(validationOfUserOrg.isRight){
  val (organization, user) = validationOfUserOrg.right.get
  print("User $user.name is in Organization $organization.id.")
} else {
  print(validationOfUserOrg.left.get.message)
}

And that's how you use Either and Option!