Every responsible web application developer is aware of the importance of online security. Since the Internet is a vital part of every business activity, from clouds to desktop or mobile devices, business software requires trusted mechanisms to make the exchange of sensitive information, like personal information or money, safe.
To avoid panic among our software customers and calm everybody down, let’s prove we can achieve and maintain this in a few steps with the Silhouette library. Everyone comfy? So buckle up and put your hands on a keyboard – it’s going to be a wild ride!
Technology stack and application goal
Over the past several years, the popularity of the Scala language has grown a lot, and more and more IT companies are deciding to choose it rather than Java. One of the most common frameworks that support and assist application development is Play Framework. In this blog post, we will see how to handle authentication of the REST API developed in the Play Scala 2.6 framework. I will walk you through the process of implementing JWT authentication with MongoDB as a storage system based on Silhouette 5.0 library capabilities.
JWT – long story in short
JSON Web Tokens, commonly known as JWTs, are tokens used for user authentication. The popularity of this technology has risen over the past few years because of the simplicity of request validation based on JWT contents. Due to this, storing data in cookies or sessions is no longer needed. With JWT, we do not need to store the access token in a database and worry about session storage. Once a user successfully logs in using their credentials, JWT is turned on and can be saved locally, for example in local storage.
To access protected resources/endpoints, the client has to send the JWT, typically in an Authorization header using Bearer schema. When a backend service gets a request with a JWT value, it validates the token. This is the flow of token validation steps:
Set up Silhouette
Since we want to configure Silhouette with MongoDB, we have to add dependencies for defined Silhouette libraries and ReactiveMongo – reactive Scala driver for MongoDB:
Then we need to set authentication configuration properties and enable respective modules:
User identity service
In Silhouette, Identity trait defines the user. User operations are handled based on an implementation of IdentityService. To store user identity data in a database, we have to develop UserServiceImpl and add one additional method for the user insert operation:
As you can see, we just implemented insert and find (by username) methods using ReactiveMongoApi.
Passwords storage DAO
The next step is to provide the implementation of DelegableAuthInfoDAO used for passwords storage operations:
We have to define JSON to case class conversion (and vice versa). In this case, we can use JSON automated mapping and the Format[T] macro.
Authenticator info – Repository
Authenticator is the heart of Silhouette – it identifies a user on every request after authentication. Below is a list of available authenticators:
- CookieAuthenticator
- SessionAuthenticator
- BearerTokenAuthenticator
- JWTAuthenticator
- DummyAuthenticator
Since we are using the header-based method – JWT in our example, the easy way out will not satisfy us anymore. Now we want to store additional information, like token duration! How?!, you may ask. First, we will need to implement AuthenticatorRepository:
Because JWTAuthenticator is a more complex object, we have to implement the JSON transformer on our own.
Registration endpoint
Now, let’s use our newly developed implementation and test the register action. For this purpose, we can gather information about unique identifier/login name, password, e-mail, first name, last name. The code below stores user account, password and passwordInfo, “sends” e-mail notifications and returns detailed token information for a new user identifier. We can use the PasswordHasher API to generate the password’s hash value.
Let’s send a request to get a register:
The application returns the following response:
Authentication endpoint
It is not needed, since the register action returns token value, but we will implement the login operation. Based on the user identifier and password, we return the token from AuthenticatorService.
For the request below:
…the application returns the following response:
Secured action with authorization
Since we have developed a secured endpoint, we can now use token authentication to access this resource.
Response is returned correctly – this means the user has access to the secured action:
And voilà. We’ve secured the application.
Serious conclusion
Securing REST Scala Play API with JWT is not a difficult task. We have so many authentication mechanisms to choose from in Silhouette. Library features like asynchronous/non-blocking operations, internationalisation or tests coverage makes it the perfect option for your application. Considering the simplicity and brevity of the Scala language, you can implement a business application with authentication very quickly.
References
You can find complete source codes for the above project on the Silhouette web site as a starter project: Silhouette REST MongoDB Seed.