4

We are designing a backend system for a large platform where users can interact with multiple products on behalf of different companies.

We plan to use Keycloak as an external identity provider. The specific implementation doesn’t matter, as it may change in the future; the important point is that there will always be an external identity provider involved.

This is, of course, a challenging task, and I would like to share some of the doubts we have. Any insight or suggestions would be greatly appreciated.

1. User Data Distribution Across the System

Our current plan is to store only the essential user data in the identity provider (for example, email and password) and keep everything else (such as profile picture, first name, preferences, and even a copy of the email) in our database.

The main reason for this is to simplify querying the user base without having to rely on the identity provider (which, in Keycloak, is not well supported).

Since we will also have a complex RBAC model, we are considering storing roles and the relationships between users, products, and companies in our own database as well.

This seems like the most reasonable approach, but are there potential issues we might encounter that would be avoided by a different approach (e.g. storing most of the data inside the identity provider)

2. User Claims

Because we plan to store roles, billing plans, and similar information in our database, another important question is how to handle user claims.

A user may have different roles for each combination of company and product. We have considered two approaches:

Option 1: Store Claims in the JWT

This seems like a clean and lightweight approach, as the JWT would include all the claims needed for authentication and authorization.

The challenge is how to issue this token.

The identity provider would need to know the user’s state in our system. One possible solution is to have an independent authorization server that returns the user’s roles for each specific product and company, which the identity provider would call whenever a user authenticates.

Option 2: Issue a Minimal JWT and Fetch Permissions Later

Alternatively, we could issue a minimal JWT and let each part of the infrastructure fetch permissions as needed.

This is simpler to implement at first but adds complexity in the long run, as every component would depend on the authorization server. Caching mechanisms would likely be necessary to prevent overwhelming it with requests.

——

Given these constraints, and given the possible solutions, what do you think we need to consider in order to achieve our goal?

9
  • when you say "external identity provider" do you mean a complete third party like facebook or google, or will you maintain control over the id system, its just external to your application? Commented Sep 4 at 19:10
  • I mean something like Okta, Auth0, Keycloak, a complete IAM. I know it sounds pretty stupid, but since there is a complex role matrixes involved, treating these tools as an IdP could be a better choice Commented Sep 4 at 19:53
  • 1
    I was mainly worried about whether you had full control over the claims or not. If you have control then roles as claims is the standard I think. You would have to check that your provider can handle the multi tenancy aspect of a single user having two accounts Commented Sep 4 at 22:09
  • i guess you also have to consider if you let the tenants edit their own users Commented Sep 4 at 22:11
  • 1
    @ikiwq, how does giving users one account across companies(/tenants?) reduce complexity? I understand how it makes the system more convenient to operate, but I don't understand how it makes the system easier to implement. Commented Sep 5 at 6:09

3 Answers 3

2

Its best practice to put role claims in the JWT and you shouldn't have to worry about role claims bloating the JWT.

However! to keep that from happening you have to be able to separate out apps and tenants of apps in the auth system.

ie I have to be able to sign in as person X, to app Y, acting as company Z and get a role set which is limited to those parameters.

Otherwise you will end up having to concatenate Y and Z parameters into the roles eg.

Admin_Teams_Microsoft Admin_Excel_Meta 

Are different "Admin" roles and now a users roles will be multiplied by the number of apps and tenants they are associated with, which could be enough to break cookie size limits or provider limits (eg OKTA role numbers)

The other problem with using the "external" ID provider for roles is if you want users of the apps to be able to manage their own permissions. To do so they will need to log into the auth system and select roles. Obviously that login and role management UI will have to be limited to the apps, users and tenants assigned to that user.

Before making a decision you have to understand if your Auth provider supports these features.

If it doesn't, then you will be forced to have a second auth layer where you fetch the roles specific to the tenant or app. This might be passed around as another jwt though.

4
  • 1
    When user is signed in into multiple organizations, do you suggest to exchange multiple JWT tokens? Commented Sep 5 at 9:29
  • 1
    I think that would be the base approach yes. A different jwt passed depending on the users selected tenant. Obvs you don't want to force multiple logins, but I don't see that as something that cant be solved. Commented Sep 5 at 11:27
  • If token exchanging is a good option, then at which level should it be performed? Should it be performed by the frontend application when the user switches between organisations? Or should it by an API Gateway, by intercepting the request and injecting the new token? Commented Sep 6 at 19:27
  • JWTs are encoded, not encrypted. Commented Sep 16 at 16:37
1

What you are describing is fine-grained access. While some of it can be expressed as claims, the bulk should be expressed in a rules engine using 'policies' (in the broad sense). This is an area known as externalized authorization or attribute-based access control (ABAC). See NIST's publication.

The architecture is as follows: Externalized Authorization Architecture

There are many frameworks that implement this for you in a flexible way:

Goal: keep your claims to a minimum and use the policies to convey access control.

2
  • If a centralized access is required for each/most requests, does JWT bring any value? Should it be abolished? What is the scaling practice here? Does every endpoint keep a copy of permissions DB? Commented Sep 15 at 12:54
  • JWT should be used to carry identity attributes e.g. the user's role, department, group... but shouldn't be used to carry more advanced claims e.g. "editDocsSales". Commented Sep 16 at 13:32
0

To start off, you don't mention Oauth2 here but I guess that's the context of this question. You mention Auth0 which has some good resources for navigating this space. I'm not sure that link helps you here specifically but I find that it helps communication a lot to understand that OAuth2 approaches vary.

We are designing a backend system for a large platform where users can interact with multiple products on behalf of different companies.

This is a little unclear to me but I understand this to mean you are supporting multiple products/services that can be accessed by users from different companies. That is, you (i.e., your employer) own and control all these products. If that's not right, please let me know.

To further check my understanding, you are definitely using an identity provider and JWTs for authentication (authn) and are trying to figure out whether and to what extent you want to use them for authorizations (authz).

If my understanding that you control all the resources, this gives you a lot of flexibility. You could simply have the JWT tell you who the caller is, and each product/service/resource would then be responsible for managing whether that user is authorized to use the service and what rights they have. If each service had it's own authorization approach, this makes a lot of sense. Of course, this also means you have more opportunities to make mistakes. You also say:

This is simpler to implement at first but adds complexity in the long run, as every component would depend on the authorization server. Caching mechanisms would likely be necessary to prevent overwhelming it with requests.

Which tells me that you have a centralized source of authorization rules.

The identity provider would need to know the user’s state in our system.

This is an interesting way to put this. The identity provider would need to know what permissions a given user has. If that's the 'state' that you are referencing, there are standard ways to manage that with identity providers with e.g., LDAP. Referencing Auth0 (they have decent docs, not an endorsement) again, they provide an AD/LDAP connector. I would expect any major player in this space to offer something similar in functionality. But if your authorization is stored in a proprietary way, that would be on you to bridge that to the provider.

If you decide it is just not worth the effort to sync authz with the identity provider, handling it directly at your authorization server isn't tremendously challenging. Your authz host could cache the responses itself, of you could cache them in intermediaries. You would be responsible for making that secure and you should not take responsibility lightly. You don't specify the volume of requests but would guess that caching at the user level or user/system level should resolve your concerns.

The issue with caching that you must consider is how long a cached authorization should be valid. It so happens that this is the same question you will need to answer if you use the identity provider to manage authorizations. That is, claims encoded on the token or in a cache will typically be valid for the lifetime of the access token. A good way to think about this is: if a user had access stripped away, what's the maximum acceptable time before that removal of access is enforced? Often a refresh token is used to allow access tokens to expire more quickly than you require reauthentication.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.