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.
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 a
IdentityStore . For example sake, we will keep Users and Tokens in Refs and hash password with BCrypt.
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).
We simply manipulate the
Map[SecureRandomId, TSecBearerToken[UserId]] inside the
Because we need to instantiate the
Ref, we provide a method that would build us a
tokens maps for
We need to lift/transform the authenticated route to a simple route and stitch it together with unauthenticated endpoints.
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:
By providing at least one user for the store to be created.
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
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 :
Final app run method:
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
- Loading configuration — https://github.com/pureconfig/pureconfig
- Parsing JSON — https://circe.github.io/circe/codecs/adt.html
- TypeLevel programming — https://github.com/milessabin/shapeless
- FP IDs - https://christopherdavenport.github.io/fuuid/
- Building Http Service — https://http4s.org/v0.21/
- Security — https://jmcardon.github.io/tsec/docs/http4s-auth.html
- Effect System — https://typelevel.org/cats-effect/datatypes/