Authenticating Users in the Play Framework

Let me introduce myself. I’m Daniel (aka QuantumBear), Cofounder of TunnelBear. My blog posts will be technical and focus on coding and development of TunnelBear apps and services.

At TunnelBear we are big fans of the Play Framework and Scala. So in my first post, I’m kicking things off with a little explanation of how to get started with user authentication in the Play framework. Along the way we will see a few common concepts used in Scala code such as functions as first class objects, case classes, pattern matching, options, implicits and traits.

First a look at what a standard API endpoint, or Action, looks like in the Play Framework v2.x:

def hello = Action { Ok("hello") }

To construct an Action we pass it some code that returns a Result (in this case, the OK result). Note that the argument to create an Action is actually a function itself. In this case a function that takes no arguments (sometimes called a code block) and that returns a Result.

Being able to pass functions as parameters like this is a key difference between Java and Scala and we will be making good use of it going forward.

For authenticated APIs, we found ourselves repeatedly checking usernames and passwords in the same way throughout the codebase. For example, if a user is defined like this:

Well it’s a method that needs to return an Action, and its argument is a username, password and a User => Result function. We just need to handle the two cases where authentication succeeds and fails, returning a Forbidden result in the failure case and executing argument function otherwise:

An Action actually takes a function of type Request => Result as an argument, where the Request holds information about the incoming http request such as it’s parameters, headers, cookies etc. So you can think of an Action as telling the Play Framework how to convert an incoming http request to a response, which it can then render.

In the above examples we didn’t need to use the Request object explicitly and so used an Action constructor which ignores the Request. Actions can also be written with the request like this:

def hello = Action { request => Ok("hello") }

In order to get at the authentication details this time, the request parameter is needed.
First a few helpers that extract useful information from requests:

parseUserFromQueryString looks for “username” and “password” http parameters in the request, and if found attempts to return the authorised user. If no user is found there, the fallback is to look for a signed cookie containing the username.

Note the use of the implicit keyword for the request parameter.

If a parameter to a function is marked as implicit, the parameter does not need to be explicitly passed in. For this to work, you have to mark a suitable value as implicit somewhere in the scope of the function.

This can clean up code where the same parameter is passed to multiple functions.

We might like to restrict an API to only those users who meet specific conditions. If we can define some traits that can be mixed in with a Controller, we can tell at a glance which users can access which API.

For example, for an API which only “premium users with a balance of at least 8” can access, constructing traits like PremiumUsersOnly and BalanceCheck might be handy. The aim is this:

Conditions:

Condition is a new type we define which is simply shorthand for “a function that takes a User and returns either a pass, or a fail”. The Either type will suit us well as a return type, being either a Right on success or a Left on failure. Either is like an extended Option that can not only signal a failure, but also hold information about the failure:

The Authentication trait holds a list of conditions which are tested after authentication is complete. If any of these Conditions fail, then we get the error message of the first one and display it to the user with a 403 Forbidden status code.

Finally we can define our traits which will add to the accessCondtions list as they are mixed in to the controller: