I'm looking for a way to avoid centralized management of authorization rules. I'd like every microservice to be responsible for the authorization logic of its actions, but I'm having some trouble implementing that. Let's use an online marketplace application as an example (like eBay). A user in this application can manage multiple online stores, and every store may be managed by multiple users. The microservice we are working on is responsible for product listings management. There is an authorization rule that says that only a manager of a store can add products to it. In order to handle the authorization check, the microservice must hold the list of stores the user manages. Let's review three ways we can achieve that:
- Call the microservice that holds the information (the one that is responsible for store management) using synchronous request/response communication. This creates coupling between them, both at the conceptual level (but it's fine in this case because they are both aware of the concept of stores anyway) and more importantly, at a technical level. If the Stores Management microservice goes down, the Product Management service won't function. This means the Product Management microservice is no longer operationally independent. Responses can be cached to minimize latency, but this won't solve the availability problem completely.
- Hold a copy of the data in a local database, that is eventually consistent with the external microservice using Integration Events. The problem with this approach is that the Product Microservice will hold too much responsibility regarding store management, and this gets even worse when other microservices need to implement a similar authorization check - they'll all have to subscribe to creation and deletion events, as well as events indicating changes in the association of users and stores, published by the Store Management microservice.
- Embed the list of stores in the user's access token (using JWT claims for example), but this feels wrong for a couple of reasons. First, associating a user to a store will require the generation of a new access token for the user (and so will other related operations). Second, I think of claims as a way to store parts of the identity of a user. Starting to save application data in them seems like a slippery slope.
I know this example may not be perfect so I'll try to generalize the problem: How can individual microservices enforce tenant isolation in an application where data for all tenants is stored in the same databases, and users may belong to multiple tenants?