#Casl with mongodb not providing correct permisions

60 messages ยท Page 1 of 1 (latest)

past raft
#

Hi! I am trying to integrate casl into my microservice that is linked to a mongo databse.

Previously I was using aggregation to get the desired Gateway(the entity in question) and return the access_level:

const gatewayAgr = await this.gatewayModel.aggregate([
      {
        $match: {
          _id: new Types.ObjectId(gatewayId)
        }
      },
      {
        $unwind: '$access'
      },
      {
        $match: {
          'access._id': new Types.ObjectId(relatedId)
        }
      },
      {
        $group: {
          _id: '$_id',
          gateway: { $first: '$$ROOT' },
          access: { $first: '$access' }
        }
      },
      {
        $project: {
          _id: '$gateway._id',
          name: '$gateway.access.name',
          access_user: '$gateway.access._id',
          access_level: '$gateway.access.access_level'
        }
      }
    ]);
    if (!gatewayAgr.length) throw new UnauthorizedException('Unauthorized access to this gateway');
    const gateway: GatewayIntercept = gatewayAgr[0];

And I am trying to migrate to a casl policy.

Here is my gateway-casl.factory.ts:

The relatedId is the user id that makes the call.

Finally, inside an interceptor I am getting the gateway and I am checking as a test if I can update the gateway. And when I retrive this gateway:

{
  _id: new ObjectId("67312444706512a8944dbf26"),
  key: '5231db1f-b79a-4dc3-a387-6f08ad7b6857',
  createdAt: 2024-11-10T21:23:16.146Z,
  blocked: false,
  access: [
    {
      _id: new ObjectId("664e641213be2c69abe6219e"),
      name: 'Babylon Dev',
      access_level: 'owner'
    }
  ],
  applied_decoders: [],
  __v: 0
}

And create the activity with this ObjectId: 664e641213be2c69abe6219e, I am getting a false for the update test.

I am down for a call of any advice you have. Please! This integration is so bad giving the deprecated documentation.

#

Casl with mongodb not providing correct permisions

clear pike
#

What do you mean by deprecated documentation? Which documentation?

As a rule of thumb and a side suggestion, you should always name your files the same as your classes.

And, because of the naming, I think you are misunderstanding what the ability builder should be doing overall. It defines abilities in general and not for a particular entity. So, naming your ability factory with "gateway" is incorrect. It's not gateways that have abilities, right? It's usually users. So, if at all, it should be called user-ability-factory.ts. In the Nest docs, it's generic to casl as in casl-ability-factory.ts

Something else I'd suggest is passing in the objectId as a string, to work with it in the builder.

Also, where or rather how are you testing the ability? What does your guard or interceptor do? (it really should be a guard).

Lastly, normally to use Casl, you should be gathering the rules via a single call to the database and it should entail already built rules i.e. a json object. This rules object should be created when the user registers (via the ability builder) and updated any time the user's permissions change (which should also run an update on the stored session - explanation follows).

When the user logs in, this rule set is found/ queried from the database and added to the user's session record. This object is also the same object you can send to the front-end to generate casl abilities there.

Now, any time the user is making a request, the session with the rules is attached to the request object, fed to something like

const abilities = new Ability(/*json array of rules from the session*/)

Note: The casl class is "Ability", but in the end, you are creating casl abilities. The author of casl is Ukrainian, and has issues with plurals , naming and English. Maybe that is your is docs issue?

clear pike
#

(had to split the text in two messages due to character limits)

The Ability function (the class) above generates the casl abilities from the rules object, which can be used in the guard to be checked against i.e. via abilities.can().

I hope that made sense. Casl and ABAC permissions in general are pretty tricky. ๐Ÿ™‚

cursive agate
#

do you use @casl/mongoose?

cursive agate
#
import { createMongoAbility } from '@casl/ability';

const abilities = createMongoAbility(/*json array of rules from the session*/)

which is totally confusing for non mongo users, in the future it will get renamed again to createPureAbility I think

clear pike
#

@cursive agate - Where did you get that from?

#

Yeah, the CASL docs suck. No two ifs, ands or buts about it.

#

It's actually not the docs, it's naming and everything about it. Very wonky design, if you ask me.

#

But, it's the only usable solution for authorization that isn't completely like pulling teeth to use (looking at casbin).

cursive agate
past raft
#

Hi @clear pike! Sorry for the late reply. I just hopped in yet another train and I am writing this on the go. So, to answer your last statement: "I hope that made sense. Casl and ABAC permissions in general are pretty tricky."

No...it makes no sense...and yes, it's tricky. Maybe I am just a little dense ๐Ÿ˜›

I will try to explain the flow as well as possible. So bare with me:

  1. A user makes a request that wants to interact with a gateway.
  2. I am getting the gateway that has an array called access. Inside this array there is a simple structure like so: {_id: <user_id>, name: <gateway_name_for_that_user>, access_level: <access_level>}
  3. Based on the access_level, the service allows certain commands for a specific gateway.

That is what I am hoping to get with this casl integration.

Note: I have named it GatewayAbilityFactory because I have more than one entity and they all have different "abilities".

There is a good chanse I am way off on a limb with this approach, but it makes the most sense for me since RBAC is not an option here.

past raft
#

What I expect form this is that the "owner" of the gateway to have all the actions to true, a maintainer to have everything except "share" action to true and any other user to have everything except "share" and "inspect" actions true.

Hence the query I set on can function: can(GatewayAction.Read, Gateway, {access: { $elemMatch: { _id: relatedId } } });

clear pike
#

@past raft - Edit after writing: I noticed I'm mixing in the term gateway app and you also have the term gateway in your use case. When I mention gateway or gateway app, I mean the server taking in client requests, not your gateway. Just wanted to make that clear before you read and despite me writing about it below too. So, on to what I initially wrote.....

You have what you need in terms of how to control access to your gateway i.e. what access should be granted to whom. What you still need to understand is how to work with casl to make that happen and it starts way before the user gets to your gateway access rule checking. I'll try again to explain (and I'm using terminology from the current casl docs -minus what hinogi pointed out).

With CASL, you need to build the rules into something. That something can be an object in runtime, called the MongoAbility or a JSON object for storage (which is what you should be doing, more on that later). Either way, that is the object you need to then compare with can, cannot to get the authorization. Your code above only shows the first part of building the rules into the MongoAbility.

The rules building should initially start, when a user is registered to the system. It's at that point, you decide what the user should have as permissions. How you store the rules is up to you, but, you should build them at this point. The JSON object you have to build yourself, but it isn't hard. And, it is much better to store the JSON object too, because you can also send this to your front end to control frontend logic based on the user's permissions (assuming you have a frontend). Or, you can take what you have in your database and remap it to the rules JSON object. That is also up to you. But, I still suggest to use a JSON object no matter.

#

When the user logs in, if you use the rules JSON storage solution, it can be read from the database as is. It is NOT built (or remapped) again. The rules data is then stored in the user's session, assuming of course, you have a sessions system setup and if you are using authorization, you must be, because that is the basis of authorization. If you aren't passing the session along to your (micro-)services in the messages to them, then you need a cache the session to call it via the user's session id. I'm not completely sure about this, but from my experience, (micro-)services shouldn't need to worry about user authorization. A gateway application (the server being called by the client, not your "gateway" system) calling the services should handle authorization. But, that is an architectural decision and irrelevant to the casl implementation. It's only relevant to the session implementation.

So, you have a user. The user logs in. The login process gets the rules for that user from the database (the JSON object is created). This object entails ALL rules for that user! The rules are added to the session and the session is now "guardian" of the system for that user along with whatever guards you implement to block or allow access. The session is usually also added to the request object, which is automatically passed around within a Nest application. Well. up to the controllers and again, it's at that point, access should be denied or allowed. However, again, if you decide to have microservices do the authorization checking per user (which I'd highly not recommend), you must find a way to get the session data with the access rules to the microservice.

In your guard, you'll have the second step of the casl authorization process working with the (as honogi pointed out), Ability function/ class. This class will take the JSON object and use it to do the comparison work so you can do abilities.can() to check against the JSON object set of rules for that user.

#

And either the user can do what they want to do, or they can't. The guard will allow the request to continue or it won't.

Oh, another reason for this solution with the JSON object. Let's assume you also wish to have a process that allows permission changes outside of your code. Let's say you have a decision to revoke access to a certain gateway. Without the JSON object, in order to change permissions, you must change the app's code, which means you must restart an app or service which might mean downtime or definitely means coordination of the app or service to shutdown only after the new app restarts. With the update of the JSON object (i.e. in the database and/ or the user's session), the permission changes can happen during runtime (via a CLI or a UI with the gateway app itself).

Not to mention, since the rules are already built, you can avoid the building of the rules during each request, which could be a performance drag on your application.

Hope you get it now. If not, ask what you don't yet understand. ๐Ÿ‘๐Ÿป

past raft
#

Ok @clear pike. I think I got it, but now I am starting to think that what I am trying to do is not possible with casl.

Form what you say, I need to provide authorisation of the user inside the service and build the rules based on that user specifically. But there is a BIG catch.

This service is inside a micro service architecture. And this specific service is a resource service, not an auth service. I do have an jwt.strategy to check the incomming requests, but the authentication part is not done on this service. I only authorise the request using an asymmetric private-public key pair. And the "gateway service" of the app does not know what entities are in the other services(why would he?). Therefor, I think I am using casl wrong here...

What do you think?

Note: Why multiple entities inside a microservice? Simple...this service is a library that glues some components placed in other micro services. Hope that makes sense.

clear pike
#

@past raft - Yes, it makes complete sense.

You said,

I do have an jwt.strategy to check the incomming requests, but the authentication part is not done on this service.

Using JWTs is authorization, NOT authentication. If a user/ client has a JWT, they've been authenticated already. In other words, in some other process to get the JWT, they were authenticated. Once the user/client has a JWT, they have access to things in your system. Theoretically, if the CASL rules were simple, you could even add them to the JWT.

So, it should be up to your authorization check of the JWT to allow or deny access and that is when you should be checking to see if the CASL rules also pass (or not).

And the "gateway service" of the app does not know what entities are in the other services(why would he?)

Correct, the gateway app doesn't know what is behind it per se. However, the service or resource being requested (through the request object) and "the rules" should be available. And, your authorization service in your gateway app can use that information to do the more finer grain authorization (via CASL) to allow or deny the request to get through.

This is why I said, your gateway app should be responsible for authorization. Think of it this way, imagine your system is an arena. Each seat of over 1000 or even 10k seats could be a microservice. At the entrance of the arena, you have what? Do you have nothing, and have to check each guest coming at their seat for their ticket? Or would you have some sort of ticket check at the entry? The ticket is the JWT. The data about where the guest should sit is data either on the ticket (it is, so the guest will know where to sit too) and also in some database, right?

This metaphore is how you should think about authorization of your system. It's an arena of possibly 1000s of seats (microservices) and you only let people in via ticket counters (gateway apps), if they have the right ticket (JWT and CASL rules pass). ๐Ÿ™‚

past raft
#

Thing is that I am using oauth2 and the tokens(access_token and refresh_token) are provided by the oauth provider. I do have the key to decode the token, but not the ones to encode it.

I think we should jump on a short call after Christmas and show you exactly what is going on as an overview. We are ping-ponging a lot for this ticket and I think it should be an easy fix, but I may be more lost than I thaught.

clear pike
#

@past raft

Thing is that I am using oauth2 and the tokens(access_token and refresh_token) are provided by the oauth provider. I do have the key to decode the token, but not the ones to encode it.

What OAuth provider is that?

#

And, in my metaphor, the OAuth provider is a ticket sales agency. ๐Ÿ™‚ And the process of selling a ticket is the login procedure in OAuth.

past raft
#

A self made and self hosted oauth provider.

clear pike
#

So, like selling a ticket and storing the seat number.

#

Orrr, you have a handover of the session in your gateway app and that process sets up the rules cache.

past raft
#

The Oauth provider is a generic one. Has no idea of the entities. It is connected to multiple apps each having different entities. I still don't get it :(.

clear pike
#

The Oauth provider is a generic one. Has no idea of the entities.

It doesn't need to know anything about the entities. It needs a process to get the rules and when the user is authenticated, to attach something to the user's access JWT to relate to the rules. Or, your gateway app can use the user's id to get that user's rules, (since authentication is already accomplished). That's the authorization handover I spoke about. But, your gateway app should then be controlling the session. Not the OAuth app.

past raft
#

Ok. Let's dive back a little bit.

The gateway service knows nothing about the other entities. It cares only if a valid access token has been provided.
The oauth provider know nothing about the other entities except the user. It cares only if the user provides valid credentials.

How can I set the rules in the gateway/oauth provider of some entities that I don't know. The roles are irrelevant. The user roles is not important. I care to sent some information based only of the access_level of the user to that gateway. That is is. Regardless of role. So as a gateway entity owner, I have certain commands and I can allow other users to see parts of the gateway entity data.

I don't understand where and how to setup the casl config for a specific user on login. For me, makes no sense...

clear pike
#

It cares only if a valid access token has been provided.

Access token. That is the key here. What access is being given? Obviously not ALL access. So, this is the missing piece.

The gateway service knows nothing about the other entities

You keep saying things like this for everything that isn't dealing with an entity. Of course they don't know about entities. The knowledge of access to entities will be put in the rules/ the permissions you set for each user. So, whatever access system you build, it needs to have a process to get these rules. And it's these rules, which will be checked at and against each request.

Let me put it another way. How can you have an authorization process, which has no clue about what permissions should be checked? Your OAuth is an authorization process. Your gateway app could also have an authorization process too (as a handover from OAuth). They need that "rules" knowledge.

How can I set the rules in the gateway/oauth provider of some entities that I don't know.

At the point the user first registers, you set the rules. When the user logs in, you get the rules and tie it to the user's session. It's the rules that determine access, because they represent the user's permission set. The request also holds what is being requested (entities, processes, needed data, etc.). Your gateway app's auth process (which I'd highly suggest should take over further authorization via sessions i.e. should have a handover), would compare the request to the user's rules and let them in or not.

I don't understand where and how to setup the casl config for a specific user on login. For me, makes no sense...

You don't set the rules up at login, you gather or retrieve them. Setup is either done during registration or when permissions change (and you also need to change any cache of the rules at that point too).

What you definitely do not want to do is set up the rules for each request. They should be readily available, like in a cache.

past raft
#

I think I am starting to dig what you are saying @clear pike . So basically, the rules for casl should be created and baked in the session/token as part of the OAUTH handshake. And I think that is the correct way to do so too.

---- STOP HERE AND RESPOND IF I AM GETTING CLOSE OR NOT ----

If you are interested in tech and you want to geek out:

Right now, I have kind of a weird handshake with the OAUTH provider that uses Postgres with UUID as primary key and the rest of the system that is Mongo predominantly Mongo(IOT project so...yeah). So in this stupid way, I have an id(UUID) corresponding to the user and an id corresponding to the one from the resource servers that marks the ownership of entities. Thinking back...it was dumb as hell, but it was easy to develop around the UUID support of Postgres.

Since your last response, I've developed a plugin for the OAUTH provider that migrates from the UUID to ObjectId(bson)-like id and I've managed to bypass the issue with support and storage by saving the id as a bytea. So right now, the system user id and the OAUTH user id are the same.

---- SIDE NOTE ----

Here is the tough pill to ask...

Thanks to the high volume of data and the need to go really deep in data encoding and compression, I have multiple services in Rust. Usually, the data collection services are in rust and the data serving services are in Nestjs. But there is one that kind of is in the middle and is in rust. So do you know a way to port these rules to Rust? I am asking this on a low chanse that you've stubble upon this problem with cross language compatibility. Not necessarily in Rust, but in any other language.

clear pike
#

@past raft - It almost sounds like you are getting it, but your last question still tells me, you aren't.

Let's back up to get me a better understanding of your system, by me asking some questions. Are there human clients hitting the system or machine clients (so other servers)? Do you have a gateway server, which offers the API to these clients? If yes, what language is it using?

past raft
#

Answer Question 1: There are both. Machine clients(basically sensor nodes) that send data to the system and user clients that can visualise data based on aggregation set by them or default ones.

Answer Question 2: Yes. That server is in Nestjs. Also, the OAUTH provider is in Nestjs as well.

clear pike
#

Ok. So a last question. Do you have separate APIs (Nest apps) for the human and machine clients? Or is it all one Nest app?

past raft
#

I have 9 services. 4 in rust(rocket) and 5 in nest. And yes, there are different for the machiene and human clients to ease the load on the services. There is only one service that sits in between and has no message broker in between.

clear pike
#

So, are your clients speaking directly to the services? I'm confused again. Sorry. ๐Ÿคท๐Ÿป

past raft
#

Ok. I will send you a .drawio with the architecture.

#

Ok. We can discuss based on this mockup.

The service that communicate directly with the Gateway app(the one that serves the Dashboard) are directly linked to it. The rest are redirects or they are communicating with the machiene clients.

Small note, Domain service is a single service. I had an initiative to split it in 3 other services and decided against it.

#

And Command Manager is not yet implemented. That service will be the communication layer between the human clients and machiene clients.

#

I think we should hear from each other again in 2025 and have a video call so we get on the same page.

clear pike
#

Ok. I get your system now. The diagram was helpful.

So, you have two services to serve the user's frontend. The Vault handles the login process the Gateway service handles routing. Both should be needed for authorization.

Your Vault service handles the login process. There should be direct communication with this service and the Gateway service for OAuth. You have to somehow verify the user's access and refresh JWTs are valid, right? If that is what you are doing, that would be a real drag on latency and why I kept saying, there should be a hand-off to the Gateway service for authz via its own session management. Then you'd only need to check the refresh JWT from the Vault for validity and only at the time the refresh is requested from the Gateway.

Is that clear? If it is, I can continue. ๐Ÿ™‚

past raft
#

Ok. So, the Gateway is checking the validity of the JWT and uses the refresh token to get a newly valid access token(and refresh token) when it expires. When the refresh token expires, then you are redirected to the Vault.

The Gateway saves the JWT in it's own session system and has nothing to do with the Vault until the refresh token is in play. I believe this is what you wanted to hear.

I think you can continue.

clear pike
#

Ok. So, that is what I was calling the handover of authorization. Instead of using your Vault for authorization checks for each request to check the session, your Gateway is running its own session. That's great!

So, at the point of user login and the first handover, the Gateway should be "collecting" whatever rules the user should have and storing them in the user's session, so at the point of the session start.

When the access JWT is checked for validity, right after that, the rules also need to be checked against information held in the request. Everything should be in the request to check against, like what resource is being hit, who the user is, what record(s) are being asked for to view or mutate and what is being asked to do (CRUD). You just have to dissect the request to get that information, then do the rules comparison.

With that comparison, the request can either be allowed through the guard, or not.

past raft
#

Ok. Let's say another piece put together in my head. The gateway is the one that makes validation of the rules.

But should I ask the respective services each of it's own entities rules or the Gateway should have them and construct them on the first handover?

#

I am asking this because I would like for the service that is responsable with the "Decoder" - just another entity in my application - to check if the request sent has access to a specific entity.

#

The system that I am developing is following a 0 trust policy.

clear pike
#

@past raft - Is the system multi-tenant? If it is, I'd understand your thinking, if it isn't, then you don't need that extra security. Your answer can form the rest of the conversation. ๐Ÿ™‚

past raft
#

Yes, it is multi-tenant.

clear pike
#

Ah. Ok. That complicates things a lot. So, I need to understand how the microservices will be built and used. I'm not at all experienced with this, but I believe, in order to serve tenants, each tenant will need its own microservice IF the logic is different per tenant. Or, if the logic is the exact same for all tenants, then the microservices can be the same, they just must know they are working for a specific tenant. Can you clarify that part of your system please?

cursive agate
clear pike
cursive agate
#

it never is but I guess it could help

past raft
#

The micro services are build in a choreography architecture. Each of them are basically responsible for a single area in the application, but have access to data related to their main entity.

For example:

In the graph that I sent you, I the registry-manager has the main objective to receive decoded data and save them in it's data registry, but has access to the gateway entity in order to determine who has access to a specific registry.

It might not be as complicated as it sounds since the main point of interest is the gatway entity. If you have access to the gateway, you can see the nodes and registry. You can't update them, but you can see them. If you are owner or maintainer of a gateway, you can see the decoders too and you can update anything regarding the gateway. Owner can grant access to other users and deny access to maintainers if he wishes so.

past raft
#

Hello @clear pike ! Long time no C! ๐Ÿ˜„

I think I got it. But I would like to check in with you.

To resume our conversation:

I have a microservice app with multiple users and different entities that are interconnected and users should have access to these entities(resources) based on their relationship with a specifc entity called gateway.

The last time we were on a stalemate on where and how to implement casl. The baseline was that form your perspective, CASL rules should always be defined somewhere in the AUTH pipeline, but my issue was that I don't have and should not have access to ANY resources in the gateway service. I should have ONLY access to user data. So, I've researched more about RBAC, CBAC, ABAC, and DBAC.

So here is the idea that I've got:

I do have the possibility to grab user data from a specific resource service(the user data specific for MY application. No passowrd, no authentification details)

Why don't I define an entity there(call it Domain) that will be linked to a gateway-entity(in this case let's call it the MASTER ENTITY) and every other entity(SLAVE ENTITY) linked to that set gateway. Now. When I define this domain, It should have an access property that is an array of definition. And set definitions should be roles and access you have to the bounded entities.

Domain = {
  _id: uuid | ObjectId | string | Buffer;
  key: string;
  access: [
    {_id: UserId, permissions: Permisions[], role: Role},
    ...
  ]
}

Gateway = {
  _id: uuid | ObjectId | string | Buffer
  ...
  domain: Domain._id | Domain.key
}

This way, on authentification pipeline, I can get a key-value pair of the domains:

  access_domains: Record<DOMAIN_KEY, {permissions: Permisions[], role: Role}>

And create the casl rule set with these. This way, I don't see why it wouldn't work corss multiple microservices

What do you think?

clear pike
#

@past raft

but my issue was that I don't have and should not have access to ANY resources in the gateway service. I should have ONLY access to user data.

With ABAC (which is what CASL offers), you have to have two things to authorize someone.

  1. an authenticated user
  2. the things he or she can or cannot do based on attributes i.e. the CASL rules.

You must know what those attributes are and what things the user can or cannot do, at the time of the person logging in, in order to authorize them.

I hope we can agree on that. Cause you wrote:

no authentification details

You must have an authenticated user.

Why don't I define an entity there

Where?

that will be linked to a gateway-entity(in this case let's call it the MASTER ENTITY) and every other entity(SLAVE ENTITY) linked to that set gateway.

Sorry, but you've completely lost me here.

And nothing after that made any sense to me. Sorry. ๐Ÿคท๐Ÿป

past raft
#

You must know what those attributes are and what things the user can or cannot do, at the time of the person logging in, in order to authorize them.

Yes we agree on that.

With ABAC (which is what CASL offers), you have to have two things to authorize someone.
an authenticated user
the things he or she can or cannot do based on attributes i.e. the CASL rules.

But on a microservice architecture, the gateway service is not linked to the databases. What do I do then? Do I declare 1 to 1 classes to the schemas / entities and create the casl rules with them?

Where?

That would be the service in which I store user data. Since the domain is user linked.

Sorry, but you've completely lost me here.

It's somewhat like this:

Hierarchy:

User has Vending Machine;

Vending Machine has Buttons;

Vending Machine has Coin Stash;


User(Role = user) -> Button(allowed);

User(Role = user) -> Coin Stash(denied);

User(Role = owner) -> Button(allowed);

User(Role = owner) -> Coin Stash(allowed);

In this case the Vending Machine is the Master Entity(all entities are linked to it) and the Button and Cash Stash are the Slave Entity.

The Domain is linked to each Vending Machine and attach to the user with it's role and permissions to that vending machine and implicit to the other entities.

Something like that. And I can create the casl rules on the Domain that will apply to ALL entities that I have linked to it.

Hope that makes sense.

clear pike
#

@past raft

But on a microservice architecture, the gateway service is not linked to the databases.

Are we speaking about a microservice or the API gateway, when you say "gateway service"? If API Gateway, it might not be connected to a database directly, but it certainly can and should access a service to log the user in (which you mentioned you are doing I believe). At that point, the user's session is set up and that user's session must entail the rules the user has in terms of permissions/ access. So, when a request hits the API gateway, you decifer the request i.e. what the user is asking to do, and use the rules from the user's session (usually stored in a cache or JWT) to allow or disallow the request to go through for that resource. It's why an API gateway is called a gateway. "Gate" being the key word. ๐Ÿ™‚

If the user is authorized to hit the resource or resolvers or whatever does the calling of your microservices, you also send along a specialized JWT with the requests/ messages to the microservices. Inside that JWT will be the specified rules for that service or all rules, depending on how you want to do it. So, now...

  1. the microservice has an authenticated and authorized request to do work, with access rules for the user and usually the user's id too.
  2. the microservice can take care of the request, knowing what it should do based on the rules in the JWT.

The rules will determine if the request is completely workable or not and your business logic can do its thing (or return a permissions error).

Since the domain is user linked.
๏ปฟ
What domain? And what does "user linked" mean? Does the user link domains together (which still doesn't make sense to me). Or is the domain linked to the user?

clear pike
#

on the Domain that will apply to ALL entities that I have linked to it.

Sorry, but this doesn't make sense to me. What does "link" mean in this context? Is it just a relationship? I feel you have some concern, I'm not understanding above access.

cursive agate
#

I think maybe something like user -> roles and roles -> abilities something like that is meant with link