Spray authenticate directive : A decoupled way to authenticate your API

Table of contents
Reading Time: 3 minutes

Organization exposes critical business data or user’s private data through API. It is required to protect API against any unauthorized access, attack or security breach. In this blog I am not going to discuss API security mechanism. Here I want to detailed out the separation of API authentication from underlying RESTful Api.

Authentication / Authorization is cross cutting concern and it must be decoupled from business logic. In this post I am going to discuss Spray’s authenticate directive which handle authentication/authorization in decoupled way.

From Spray’s documentation.
“Directives” are small building blocks of which you can construct arbitrarily complex route structures.

A directive does one or more of the following:

  • Transform the incoming RequestContext before passing it on to its inner Route
  • Filter the RequestContext according to some logic, i.e. only pass on certain requests and reject all others
  • Extract values from the RequestContext and make them available to its inner Route as “extractions”
  • Complete the request

 authenticate directive is nothing but a special directive with takes a special function which would be used to authenticate inbound requests. At lowest level authenticate takes Future[Authentication[T]] or ContextAuthention[T] as argument.

Future[Authentication[T]] takes authentication data from lexical scope, while ContextAuthentication[T] takes authentication data from RequestContext. Actually ContextAuthentication is a higher order function which takes RequetContext as argument and return Future[Authentication[T]] .

Let’s take an example to see how this nice feature can be a useful tool to authenticate the api in decoupled way.

There are lot of available implementations build over authenticate directive like UserPass authenticator, Token Authenticator, Http Authenticator and so on. Recently I was working on a project where It is required to authenticate the api against access token, user pass or app_key / app_secret. I want to use a generic authenticator to do all kind of authentication so I decided to tweak existing implementation. In this implementation base trait is RestAuthenticator.scala. Code looks as follows

Different type of authenticator can be constructed by extending RestAuthenticator. In derived class we just need to supply two things which are abstract in RestAuthenticator.

a) keys : Parameters which need to extract from query parameters. It may be “access_token” In case AccessTokenAuthenticator OR “app_key” and “app_secret in case of AppAuthenticator.

b) authenticator : This function contains custom logic to authenticate credentials or token.

Following is an example of AccessTokenAuthenticator.

Following is a UserPassAuthenticator.

Both of the Authenticators are parameterized case classes so we can supply dummy authenticator function while testing.

Integrate the authenticators with routes

Following route shows how authenticators can be composed. Here userPassHandlerForTest and appCredentialHandlerForTest has been composed to validate app and user’s credentials.

Code can be pulled from github.

Written by 

Mayank is a polyglot programmer who believes in selecting the right tool for the job. He has more than 8-year experience in Java Platform. He has been a Scala enthusiast ever since he came to know this beautiful language in 2010. He has been developing enterprise applications on the reactive stack. He's a big fan of agile development, scalable software and elegant code. Mayank has extensive knowledge in a huge spectrum of areas of software, and the ability to dive deeply into a new technology and achieve expert level in no-time. He found fun to architect complex systems in the simplest way and quite handy in Design patterns, micro-services & DevOps technologies. On the personal front, he is a marathon runner, spiritual learner & yoga practitioner.

2 thoughts on “Spray authenticate directive : A decoupled way to authenticate your API4 min read

Comments are closed.