Using API Gateways and JWTs for Identity Management in Microservice Based APIs

Image Courtesy of jwt.io

Microservices are still a hot topic in software architecture, with the advances in containerisation of applications making their development, deployment and management much easier. There are of course a number of challenges one faces when choosing to adopt a microservices architecture, however one interesting area is identity management, particularly when discussing APIs. By utilising JWTs and an API Gateway, a microservices based API can benefit from reducing the amount of service to service interactions by passing the full user identity in each request within the microservices ‘network’ and thus reduce the need for duplicated calls to a user information service.

Slow down speed racer! What is an API Gateway?

In an article for Nginx, Chris Richardson provides a good definition of an API Gateway:

An API Gateway is a server that is the single entry point into the system. It is similar to the Facade pattern from object-oriented design. The API Gateway encapsulates the internal system architecture and provides an API that is tailored to each client — Chris Richardson, CloudFoundry

Effectively, the API gateway is an intermediary which services API requests by either routing the request to the relevant microservice, or dispatching a number of requests and aggregating the responses. The gateway can take care of functions common API concerns such as rate-limiting, caching, logging, transformations and more.

About JSON Web Tokens (JWT)

A JWTs are a method for transmitting information securely between two parties, and are particularly useful in the context of authentication.

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed — JWT.io

When a user successfully authenticates themselves using, for example, a username and password, the user can be returned a JWT, generated by the party servicing the request, which they must supply when making future requests. The application on the receiving end of these future requests can decode the JWT and in doing so successfully, identify the user. If the JWT has been tampered with, it will be invalid and the request will be rejected. A JWT has 3 parts: a header, payload and signature. The great thing about JWTs is that the ‘payload’ part of a JWT can be used to store custom information, which as we will see, is a great place to include user details.

So how do API Gateways and JWTs fit together and why does it even matter?

Request authentication is an ideal candidate for a function which should be managed an API Gateway. As a request comes in, one of the first jobs a system will do is decide whether the request should be serviced. It is inefficient to have every microservice take on the overhead of authenticating the user, and then loading the user details from the user information microservice. Instead, we can have the API Gateway authenticate the request, therefore removing the need for what would likely be duplicated authentication effort within each service, and the API Gateway can pass on an identifier that the upstream microservices can use. If we take a look at the Kong Api Gateway, with the aid of the official Kong JWT authentication plugin, ir does exactly this. It issues and verifies JWTs, and after successful authentication it will append either an X-Consumer-Username or X-Consumer-Custom-ID parameter to the upstream service. At this point, we’ve demonstrated how JWTs can be used for authentication by an API gateway, but the usage of a JWT at this point is not providing significant benefits as opposed to using some other form of token. Individual microservices will still face the challenge of needing to load the user information, probably by using a user information microservice.

Luckily, this is where the payload section of JWTs comes to the rescue. The API Gateway can manage authentication whichever way it likes, for example, exposing an auth endpoint which accepts a Username/Password combination and returning a token of some sort for future requests. The token could be a JWT, or it could be some other form of token. However, upon verifying this ‘public facing token’, the API Gateway can then load the user details from the user information microservice, and generate a JWT containing this user information in the payload section of this new JWT, which will then be passed on the requests it makes to the microservices. Once a microservice receives a request, it can decode and verify signature of the JWT and obtain the user information it needs from the JWT payload without the need to contact the user information service. Additionally, each microservice can then include this JWT to any other microservices which they call themselves, all the while token sent out into the public world by the API Gateway is completely separate and can contain the minimum information required.

An example: An eCommerce Retailer

Consider an eCommerce Retailer with various points of sale such as mobile apps and a web store, and a microservices based API that supplies information to these clients. In order to load a given page or screen, a client will most likely need information from more than one of the individual microservices. As a starter, let’s take a look at the home page for the web store. It’s likely that in order to load this page, we will require the following information:

  • Catalog Service: Product details such as description, brand, dimensions etc.
  • Recommendation Service: Recommended products for the current user based on their country, order history and other factors
  • Promotions Service: Promotions and offers available for the customer type of the current user (e.g. Premium)
  • Reviews Service: Reviews of the product from the current user’s country
  • Basket Service: The current status and contents of the current users active basket

There could be other information required, but let’s stick to what we’ve got for now. As I’ve already explained, an API gateway can be used to help orchestrate the gathering of this information in response to a client request, rather than exposing all the required microservices and having the client fire off a number of requests to each. As an organisation grows, it’s possible these services may be split further, and some of these microservice may be legacy systems developed by different teams and therefore not adhering to the same protocols/patterns. The key benefits of the API gateway here should be obvious:

  • The API gateway can expose user-friendly, client specific endpoints whilst handling the data transformation and service discovery via a service registry
  • Performance gains can be realised by allowing the gateway to orchestrate the asynchronous loading data from the required services, and hide this complexity behind a simple endpoint such as /product/{id}
  • From a client point of view, it’s much more simple!

However, if we consider things from authentication point of view, each of the requests to the individual microservices depend heavily on user information such as the user country. By passing the full identity of the user on each Gateway/service to service request, each service may be able to skip the user information service call, and thus we have a unified mechanism for identity management within our microservices architecture, and have increased the efficiency with which we process requests.

Summary

Authentication is an important area when building any system, but in a microservices based API, individual microservices should be responsible for Authorisation, and delegate authentication to an API Gateway. By using making a distinction between the tokens it sends out into the public vs the tokens which are used when making requests to a microservice, an API Gateway can use JWTs to create a more efficient, uniform identity management system within a microservices architecture.