How JWT can help you solve authentication between several micro-services
Here’s the thing, when you have several micro-services (or big services, if you prefer), you will face authentication trouble. Some of your endpoints will need to be secured – with or without specific permissions like admin, guest, or user – and ensure queries are not damaged by anyone.
One may think that we only need to add auth service and create user logins. But how and where is the logged session metadata stored?
In this specific auth service? It would be slow to interrogate this service on each query from all the existing micro-services. And this will create a huge bottleneck.
In the client side of things? Why not, but how does one store this? And how can we ensure information is not altered, since it’s the user side?
To help solve this, we will go over a classic JWT (JSON Web Token) pattern as singleSignOn mechanism. The pattern will ensure some major key security points:
- Authenticity and Trustworthiness (is the data falsified or trustworthy?)
- Integrity (is the data altered?)
- Availability (is the data easy to access or handle?)
Confidentiality will not be treated during this topic, but it is really easy to add by yourself if you’d like.
This is a classic use case with several services communicating with each other.
We only want the user to log in once, by typing their password, and an authentication system interface to check their credentials using a CAS system, database, Auth or any other system for example.
Our solution doesn’t provide an Auth system, but it’s more a transportation, sharing and storage system for the session. To check credentials and be able to share and store sessions is two different things.
Auth Session Token
The current solution is to store sessions in a small token stored by the client (localStorage) and to send along each query to micro-services. This token is generated by a trusted authority, has expiration date and can be forwarded between each service.
Authenticity and Trustworthiness is ensured by a public / private key. The token is forged by the authority and signed with a private key. Each micro-service has the public key of the authority and can check the signature with it.
For Integrity, the token is shipped with a hash so we can check the received signed hash with the one generated on data reception. This is a classic sign / hash system.
Because there is no external call (DB access), each query is sent along in Headers and the check is really fast, the mechanism can be considered good regarding the Availability.
We will create an interceptor in our vue.js stack to catch all outgoing queries and add the JWT stored from localStorage to the query header. In the other side, the protected endpoint will be decorated (Python) to handle the incoming query and to check the JWT in the header.
JSON Web Token (JWT)
JSON Web Token are plain texts with base64 encoded. It can be split in three parts:
Stored by the client, created by the authority
Header + Payload + Signature
Here is a flow diagram for each protected endpoint. We return a HTTP error if needed.
To make this possible, we need to create 2 decorators and some useful functions.
Get the token from the AuthorizationBearer header.
Check if the signature is valid.
Decode the token and check the validity. If everything is good, the function passes the token payload to the endpoint in parameters.
We create a new decorator to check if the user has the correct permission level for the given endpoint. It can be whatever you want, like admin, user, guest, dev, etc.
And finally, the token generator function.
This is an example for the login function.
And now the easy part, protect an endpoint. Our authentication between micro-services is almost done!
This should be relatively easy. Since we are using Axios, we only need to add a HTTP interception to add the token onto each query. By using this, we don’t need customs logic or anything like that.