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
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
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.
And finally... my servlet! Short and sweet.