I have been thinking a lot recently about how microservice based approaches can work for me in resolving many of the problems I encounter. The trouble is there is a tonne of information on the subject and working out a clear definition of a microservice is not easy. I needed to work out what I think a microservice actually is. (See https://code.metcarob.com/node/245). To do this I want to build an experimental microservice to see how the technical challenges pan out.
I already have built a ‘security’ service which provides a façade for LDAP to generate JWT tokens (https://github.com/rmetcalf9/kong_ldap_login_endpoint) but there are some things I don’t like about this:
- It has no frontend and requires every webapp to build it’s own login screen
- It only authenticates via LDAP (So no google login, no log in with facebook etc.)
- I want to experiment with a new passwordless log in method (https://www.grc.com/sqrl/sqrl.htm )
- I want a multi-tenant solution
- I want to experiment with cloud datastores and more automated deployments
The high level design for this is something like this:
The security microservice would be independantly deployable from webapps and have separate data stores, application and reverse proxy rules. This experimental microservice is extendable so support for different log in methods can be added. This is not possible in my original version since it would require the ui for each new login method to be added to every webapp that uses it.
Using the magic of URL's the end user can swap between the WebApp and the login screen. This works because the login screen is able to drop a cookie into the browser and when the user is sent back to the WebApp it can use the security token to access the protected services. I was able to develop an admin frontend using the same principle!
As my design evolved the question of storing user emails and having email verification came up. In order for a user to reset their passwords I would like to get them to send a one time login token to a verified email address. I wresteled with two possible options to achieve this:
- Put email and email verification functionality into the Security Microservice
- Create a separate Email verification service
If I put email address verification functionality into the security microservice it suddenly becomes responsible for storing users emails, but where does this end? What about user photos? What about mailing list opt-in/opt-out options? I want to avoid this so even though it seems like a lot of extra effort just for a small extra field I think I want to build a separate user messaging microservice:
I think I might be thinking along the right lines here as introducing a whole new service just for emails is truly micro!
In this design the Security microservice can call the User messaging service when it needs to send the user a reset password link. Each set of features can be individually built, version controlled and deployed using their own cycles even by different teams or organisations.
This process works well and can be extended, if the team running the messaging service decide they need to provide a UI to the user to allow email address changes it is simple to add one.
This can be extended further. I can create a generic user data microservice which stores JSON objects for each user, shopping carts, account functions, order functions etc. can all be added independently. Each can provide its own UI.
I still have some future questions to explore:
- Could Microservice expose their UI as components rather than full web apps? - Components could be integrated in a single thin webapp layer.
- Is it better for microservices to just expose API’s and stable contracts rather than have their own UI?
- How would traditional integrations fit in?
Linking different microservices
An important thing to note with the design is that some data needs to be agreed apon between microservices in order to link data together. In this case the user needs to be linked with their email address. I have chosen to use a text UserID for this purpose, but I think I made a mistake here. You see UserID is a human readable field and humans sometimes put in a request to change the value. The impact of changing any field that is used to link data between microservices is high and its a cross cutting concern. I think it would be far better to use guids to link data across systems.
As well as not being subject to humans wanting to change them guids have other advantages. They have a commonly accepted standard definition, they are safe to use as part of URL’s, and their random factor means they don’t require a central issuing authority. Luckly I have also implemented a separate known as field so I can alter my microservice to use guid’s as user identifiers and keep showing users the value of the known as field.