Authentication & Authorization in a Microservices Architecture (Part 1)
IT Tips & Insights: A Softensity Engineer kicks off a three-part series comparing the way solutions can be designed in a monolithic architecture versus a microservices architecture.
By Gustavo Regal, Software Engineer
Just Enough Microservices
Microservices have proven themselves worthy for more than a decade now. This architectural system suits large systems that need to be developed by lots of people. Nonetheless, it doesn’t come without a cost. One of its main benefits is loose coupling, which is the result of a set of very well distinguished components (services) that:
- Have a single responsibility (which every component should, right?), often defined around business capabilities (payment, ordering, delivering …).
- Interact with each other to perform user/application transactions.
- Have STRONG borders (i.e, separate databases, separate codebases, kept by different teams, only interact through well defined network interfaces, such as REST APIs, gRPC, messages/events …).
Unfortunately, this excellent advantage is also its Achilles’ heel! When you separate the applications modules (subdomains, contexts, whatever) in different systems, you may struggle with:
- Code reuse: need to rethink that paradigm.
- Data replication: you may now have to keep copies of the same data in different places, in different arrangements, for different reasons.
- Eventual consistency: because of the previous item, you will probably have to accept eventual consistency and all its implications at a given point, if not right from the start.
- Operations: now you have lots of things to build, test, deploy, monitor, etc.
At the end of the day, companies are realizing that this kind of architecture provides more productivity and it pays off, hence it’s becoming more popular each and every day.
Just Enough Authentication and Authorization
Here we have two similar words that are often misinterpreted or misused.
- Authentication: to be sure of who is there, who is calling
- Authorization: to verify what permissions or privileges they have
One famous misnomer is the HTTP Header called Authorization, which is normally used to carry an authentication token. A second one is the HTTP 401 Status (Unauthorized), which actually means “unauthenticated” (403 Forbidden should be used to indicate lack of privileges).
Authentication in a Monolithic Application
Let’s say you have a monolithic application: One single database. One single backend service. One single frontend app.
A common way to design authentication would be the following:
1. If app tries requesting any data or operation without sending an authentication token or session id, then the backend will deny it, returning status 401 Unauthorized:
2. If the app receives a status 401, then it knows the user must authenticate (sign in), thus it presents them with a login form. User fulfills and app posts their credentials (username, password) to the backend, which will respond with status 200 OK (if OK) and some type of authentication token (either a JWT in the response body or a session id as a cookie in the response headers):
3. Done! User is authenticated and can now use the apps features, whose requests to the backend will now be accepted since they carry something that allows to identify the user:
If we zoom in a bit, we’ll see the backend portion of the system storing in-memory and/or persistent data about users, their credentials and their sessions:
Authorization in a Monolithic Application
Once a user is identified/authenticated, the system can now determine what that user can or cannot do. That should be quite easy, as you only need to have data defining:
- The user’s role in the business
- The role’s permissions
- The relationships between the user and the objects/document/data they are trying to access/manipulate
Items 1 and 2 refer to a method called RBAC (Role-Based Access Control) or role-based authorization, i.e the privileges to perform operations/functions are granted to a user based on the roles assigned to them.
Example: every user with the “Salesperson” role assigned is allowed to create sales orders.
Item 3 refers to a method LBAC (List-Based Access Control) or authorization based upon access-control lists (ACLs), in which permissions to access or manipulate any object/collection are granted or denied based on the relationship the user holds with such data.
Example: although every user in the “Salesperson” role inherits permission to “Query sales orders,” they can only access the orders created by themselves, i.e there is a clear link between the user object and the sales_order object in the database.
Nothing too spectacular so far, so in Part 2 we are going to determine what complexities arise and how to tackle them when we talk about microservices architecture.
Hey, I’m Gustavo Regal. I live in Porto Alegre (Brazil) and I’ve been a software engineer and a few more things since 2007, during which time I have designed and developed lots of different kinds of systems for all sorts of industries.
I am currently working as a tech lead and architect at Softensity, building distributed solutions using Azure, C# and other software.
Thank you for taking the time to read this blog. I would love to get your feedback and contributions.