Security – Authorization and Authentication System for Microservices

authenticationauthorizationmicroservicesSecurity

We plan to refactor our company system into a micro-service based system. This micro-services will be used by our own internal company applications and by 3rd party partners if needed. One for booking, one for products etc.

We are unsure how to handle roles and scopes. The idea is to create 3 basic user roles such as Admins, Agents and End-Users and let the consumer apps to fine-tune scopes if needed.

  • Admins can create, update, read and delete all
    resources by default (for their company).
  • Agents can create, update and read data for their company.
  • End-Users can create, update, delete and read data, but cannot access same endpoints as agents or admins. They will also be able to create or modify data, just not on a same level as agents or admins. For example, end users can update or read their account info, same as agent will be able to do it for them, but they can't see or update admin notes.

Let's say that agents by default can create, read and update each resource for their company and that is their maximum scope which can be requested for their token/session, but developers of client (API consumer) application have decided that one of their agents can read and create only certain resources.

Is it a better practice to handle this in our internal security, and let them write that data in our database, or let clients handle that internally by requesting a token with lesser scope, and let them write which agent will have which scope in their database? This way we would have to track only token scopes.

The downside of this, is that our team would also need to create fine-tuned access mechanisms in our internal applications.

With this way of thinking, micro-services and their authorization system should not be bothered with clients needs, because they are only consumers and not part of the system (even though some of those consumers are our own internal apps)?

Is this delegation a good approach?

Best Answer

Authentication and authorization are always good topics

I will try to explain to you how we deal with authorizations in the current multi-tenant service that I am working. The authentication and authorization are token based, using the JSON Web Token open standard. The service exposes a REST API that any kind of client (web, mobile, and desktop applications) can access. When a user is successfully authenticated the service provides an access token that must be sent on each request to the server.

So let me introduce some concepts we use based on how we perceive and treat data on the server application.

Resource: It is any unit or group of data that a client can access through the service. To all the resources that we want to be controlled we assign a single name. For instance, having the next endpoint rules we can name them as follow:

product

/products
/products/:id

payment

/payments/
/payments/:id

order

/orders
/orders/:id
/orders/:id/products
/orders/:id/products/:id

So let's say that so far we have three resources in our service; product, payment and order.

Action: It is an operation that can be performed on a resource, like, read, create, update, delete, etc. It is not necessary to be just the classic CRUD operations, you can have an action named follow, for instance, if you want to expose a service that propagates some kind of information using WebSockets.

Ability: The ability to perform an action on a resource. For instance; read products, create products, etc. It is basically just a resource/action pair. But you can add a name and description to it too.

Role: A set of abilities that a user can own. For example, a role Cashier could have the abilities "read payment", "create payment" or a role Seller can have the abilities "read product", "read order", "update order", "delete order".

Finally, a user can have various roles assigned to him.


Explanation

As I said before, we use JSON Web Token and the abilities that a user possesses are declared in the payload of the token. So, suppose we have a user with the roles of cashier and seller at the same time, for a small retail store. The payload will look like this:

{
    "scopes": {
        "payment": ["read", "create"],
        "order": ["read", "create", "update", "delete"]
    }
}

As you can see in the scopes claim we don't specify the name of the roles (cashier, seller), instead, just the resources and the actions that are implicated are specified. When a client sends a request to an endpoint, the service should check if the access token contains the resource and action required. For example, a GET request to the endpoint /payments/88 will be successful, but a DELETE request to the same endpoint must fail.


  • How to group and name the resources and how to define and name the actions and abilities will be a decision made by the developers.

  • What are the roles and what abilities will have those roles, are decisions made by the customers.


Of course, you must add extra properties to the payload in order to identify the user and the customer (tenant) that issued the token.

{
    "scopes": {
        ...
    },
    "tenant": "acme",
    "user":"coyote"
}

With this method, you can fine-tune the access of any user account to your service. And the most important, you don't have to create various predefined and static roles, like Admin, Agents, and End-Users as you point out in your question. A Super User will be a user that owns a role with all the resources and actions of the service assigned to it.

Now, What if there are 100 resources and we want a role that gives access to all or almost all of them?. Our token payload would be huge. That is solved by nesting the resources and just adding the parent resource in the access token scope.


Authorization is a complicated topic that must be addressed depending on the needs of each application.

Related Topic