Http4s service with authentication using TSec

Algimantas Krasauskas
Wix Engineering
Published in
3 min readFeb 11, 2020
Photo by Max Duzij on Unsplash

When starting to developer apps in a different programming style, it’s common to get bog down by tooling and a multitude of libraries that promise to follow the pattern that you are preaching. This post plans to minimize this friction for Scala developers planning to create an Http service that would adhere to Functional Programming(FP) patterns.

As you can guess from the name of the post, we will be using Http4s for our Http layer and TSec for the authentication. For simplicity, we will use a single effect system Cats-Effect and transform our request payload to/from JSON with Circe. For ID’s we will use FUUID that we will tag with Shapeless.

Simple beginnings

To get our feet wet, we can start just by building a simple Http Service without any authentication. We provide HttpRoutes that can be transformed into HttpApp that matches all provided routes or returns 404 route as a fallback.

Introducing authenticated routes

One of the easiest ways to add authentication to your Http4s App is to use TSec. It provides you with Authentications for Cookies, Bearer Tokens, JWT’s and even lets you integrate to use Authorization strategies. For this example, we will use for authentication. Bearer token Authenticator requires us to create BackingStore and aIdentityStore . For example sake, we will keep Users and Tokens in Refs and hash password with BCrypt.

UserStore:

To have type-safe IDs, we need to tell the compiler that even though the underlying type is FUUID, it’s different than other FUUIDs. Shapeless also provides us with a way to build helper methods def tagFUUIDAsUserId(id: FUUID): UserId = tag[UserIdTag][FUUID](id).

Token Store:

We simply manipulate the Map[SecureRandomId, TSecBearerToken[UserId]] inside the Ref.

Authenticator:

Because we need to instantiate the Ref, we provide a method that would build us a users and tokens maps forauthenticator .

Secure Route:

New HttpApp:

We need to lift/transform the authenticated route to a simple route and stitch it together with unauthenticated endpoints.

Login Route

So we managed to create an API that requires you to authenticate the next step is to provide a way to authenticate. For that, we need to provide a way to send user details in some form and attach the token to the response.

Encapsulating the UserStore:

To be able to check if users exist, we need a way to tap into the list of users and validate that the user credentials provided are valid.

This requires us to provide a general construction of UserStore, that would give away to create and validate users.

Create new users:

By generating and ID and hashing the provided password.

Validate existing users:

Build UserStore:

By providing at least one user for the store to be created.

LoginRoute:

We provide a JSON decoder to be able to extract UsernamePasswordCredentials from JSON payload we will submit a login request. In the response, if the login is successful, we will use authenticator to embed the token to the response.

HttpApp with Login:

Loading Config from the Environment

Embedding username and password into the code seems like a bad idea, so let’s replace that by providing a config with this and few other options. Let’s simplify this task by using PureConfig with Cats-Effect. Lets set resources/application.conf to :

Matching Config:

Final app run method:

Summary

Developing in FP style tends to provide you with easy to use composable bits of code, as well as libraries that are maturing quickly and provide elegant APIs. I hope this post gave you a glimpse of tooling that you might use to solve Http or authentication-related problems.

Example code + additional examples: https://github.com/Algiras/secure-api-example

Resources:

--

--

Algimantas Krasauskas
Wix Engineering

Engineer that strives for excellence and growth. Currently working at @Wix and loving it!