Resources, scopes, permissions and policies in keycloak - permissions

I want to create a fairly simple role-based access control system using Keycloak's authorizaion system. The system Keycloak is replacing allows us to create a "user", who is a member of one or more "groups". In this legacy system, a user is given "permission" to access each of about 250 "capabilities" either through group membership (where groups are assigned permissions) or a direct grant of a permission to the user.
I would like to map the legacy system to keycloak authorizations.
It should be simple for me to map each "capability" in the existing system to a keycloak resource and a set of keycloak scopes. For example, a "viewAccount" capability would obviously map to an "account" resource and a "view" scope; and "viewTransaction" maps to a "transaction" resource... but is it best practice to create just one "view" scope, and use it across multiple resources (account, transaction, etc)? Or should I create a "viewAccount" scope, a "viewTransaction" scope, etc?
Similarly, I'm a little confused about permissions. For each practical combination of resource and scope, is it usual practice to create a permission? If there are multiple permissions matching a given resource/scope, what does Keycloak do? I'm guessing that the intention of Keycloak is to allow me to configure a matrix of permissions against resources and scopes, so for example I could have permission to access "accounts" and permission for "view" scope, so therefore I would have permission to view accounts?
I ask because the result of all this seems to be that my old "viewAccount" capability ends up creating an "Account" resource, with "View" scope, and a "viewAccount" permission, which seems to get me back where I was. Which is fine, if it's correct.
Finally, obviously I need a set of policies that determine if viewAccount should be applied. But am I right that this means I need a policy for each of the legacy groups that a user could belong to? For example, if I have a "helpdesk" role, then I need a "helpdesk membership" policy, which I could then add to the "viewAccount" permission. Is this correct?
Thanks,
Mark

Full transparency- I am by no means a Keycloak/OAuth/OIDC expert and what I know is mostly from reading the docs, books, good ol' YouTube and playing around with the tool.
This post will be comprised of two parts:
I'll attempt to answer all your questions to the best of my ability
I'll show you all how you can play around with policies/scopes/permissions in Keycloak without needing to deploy a separate app in order to better understand some of the core concepts in this thread. Do note though that this is mostly meant to get you all started. I'm using Keycloak 8.0.0.
Part I
Some terminology before we get started:
In Keycloak, you can create 2 types of permissions: Resource-Based and Scope-Based.
Simply put, for Resource-Based permissions, you apply it directly to your resource
For Scoped-Based permission, you apply it to your scope(s) or scope(s) and resource.
is it best practice to create just one "view" scope, and use it across multiple resources (account, transaction, etc)? Or should I create a "viewAccount" scope, a "viewTransaction" scope, etc?
Scopes represent a set of rights at a protected resource. In your case, you have 2 resources: account and transaction, so I would lean towards the second approach.
In the long run, having a global view scope associated with all your resources (e.g. account, transaction, customer, settlement...) makes authorization difficult to both manage and adapt to security requirement changes.
Here are a few examples that you can check out to get a feel for design
Slack API
Box API
Stripe
Do note though - I am not claiming that you shouldn't share scopes across resources. Matter of fact, Keycloak allows this for resources with the same type. You could for instance need both viewAccount and viewTransaction scope to read a transaction under a given account (after all you might need access to the account to view transactions). Your requirements and standards will heavily influence your design.
For each practical combination of resource and scope, is it usual practice to create a permission?
Apologies, I don't fully understand the question so I'll be a bit broad. In order to grant/deny access to a resource, you need to:
Define your policies
Define your permissions
Apply your policies to your permissions
Associate your permissions to a scope or resource (or both)
for policy enforcement to take effect. See Authorization Process.
How you go about setting all this up is entirely up to you. You could for instance:
Define individual policies, and tie each policy under the appropriate permission.
Better yet, define individual policies, then group all your related policies under an aggregated policy (a policy of policies) and then associate that aggregated policy with the scope-based permission. You could have that scoped-based permission apply to both the resource and all its associated scope.
Or, you could further break apart your permissions by leveraging the two separate types. You could create permissions solely for your resources via the resource-based permission type, and separately associate other permissions solely with a scope via the scope-based permission type.
You have options.
If there are multiple permissions matching a given resource/scope, what does Keycloak do?
This depends on
The resource server's Decision Strategy
Each permission's Decision Strategy
Each policy's Logic value.
The Logic value is similar with Java's ! operator. It can either be Positive or Negative. When the Logic is Positive, the policy's final evaluation remains unchanged. When its Negative, the final result is negated (e.g. if a policy evaluates to false and its Logic is Negative, then it will be true). To keep things simple, let's assume that the Logic is always set to Positive.
The Decision Strategy is what we really want to tackle. The Decision Strategy can either be Unanimous or Affirmative. From the docs,
Decision Strategy
This configurations changes how the policy evaluation engine decides whether or not a resource or scope should be granted based on the outcome from all evaluated permissions. Affirmative means that at least one permission must evaluate to a positive decision in order grant access to a resource and its scopes. Unanimous means that all permissions must evaluate to a positive decision in order for the final decision to be also positive. As an example, if two permissions for a same resource or scope are in conflict (one of them is granting access and the other is denying access), the permission to the resource or scope will be granted if the chosen strategy is Affirmative. Otherwise, a single deny from any permission will also deny access to the resource or scope.
Let's use an example to better understand the above. Suppose you have a resource with 2 permissions and someone is trying to access that resource (remember, the Logic is Positive for all policies). Now:
Permission One has a Decision Strategy set to Affirmative. It also has 3 policies where they each evaluate to:
true
false
false
Since one of the policies is set to true, Permission One is set to true (Affirmative - only 1 needs to be true).
Permission Two has a Decision Strategy set to Unanimous with 2 policies:
true
false
In this case Permission Two is false since one policy is false (Unanimous - they all need to be true).
Now comes the final evaluation. If the resource server's Decision Strategy is set to Affirmative, access to that resource would be granted because Permission One is true. If on the other hand, the resource server's Decision Strategy is set to Unanimous, access would be denied.
See:
Resource Server Settings
Managing Permissions
We'll keep revisiting this. I explain how to set the resource sever's Decision Strategy in Part II.
so for example I could have permission to access "accounts" and permission for "view" scope, so therefore I would have permission to view accounts?
The short answer is yes. Now, let's expand on this a bit :)
If you have the following scenario:
Resource server's Decision Strategy set to Unanimous or Affirmative
Permission to access the account/{id} resource is true
Permission to access the view scope is true
You will be granted access to view the account.
true + true is equal to true under the Affirmative or Unanimous Decision Strategy.
Now if you have this
Resource server's Decision Strategy set to Affirmative
Permission to access the account/{id} resource is true
Permission to access the view scope is false
You will also be granted access to view the account.
true + false is true under the Affirmative strategy.
The point here is that access to a given resource also depends on your setup so be careful as you may not want the second scenario.
But am I right that this means I need a policy for each of the legacy groups that a user could belong to?
I'm not sure how Keycloak behaved 2 years ago, but you can specify a Group-Based policy and simply add all your groups under that policy. You certainly do not need to create one policy per group.
For example, if I have a "helpdesk" role, then I need a "helpdesk membership" policy, which I could then add to the "viewAccount" permission. Is this correct?
Pretty much. There are many ways you can set this up. For instance, you can:
Create your resource (e.g. /account/{id}) and associate it with the account:view scope.
create a Role-Based Policy and add the helpdesk role under that policy
Create a Scope-Based permission called viewAccount and tie it with scope, resource and policy
We'll set up something similar in Part II.
Part II
Keycloak has a neat little tool which allows you test all your policies. Better yet, you actually do not need to spin up another application server and deploy a separate app for this to work.
Here's the scenario that we'll set up:
We'll create a new realm called stackoverflow-demo
We'll create a bank-api client under that realm
We will define a resource called /account/{id} for that client
The account/{id} will have the account:view scope
We'll create a user called bob under the new realm
We'll also create three roles: bank_teller, account_owner and user
We will not associate bob with any roles. This is not needed right now.
We'll set up the following two Role-Based policies:
bank_teller and account_owner have access to the /account/{id} resource
account_owner has access to the account:view scope
user does not have access to the resource or scope
We'll play around with the Evaluate tool to see how access can be granted or
denied.
Do forgive me, this example is unrealistic but I'm not familiar with the banking sector :)
Keycloak setup
Download and run Keycloak
cd tmp
wget https://downloads.jboss.org/keycloak/8.0.0/keycloak-8.0.0.zip
unzip keycloak-8.0.0.zip
cd keycloak-8.0.0/bin
./standalone.sh
Create initial admin user
Go to http://localhost:8080/auth
Click on the Administration Console link
Create the admin user and login
Visit Getting Started for more information. For our purposes, the above is enough.
Setting up the stage
Create a new realm
Hover your mouse around the master realm and click on the Add Realm button.
Enter stackoverflow-demo as the name.
Click on Create.
The top left should now say stackoverflow-demo instead of the master realm.
See Creating a New Realm
Create a new user
Click on the Users link on the left
Click on the Add User button
Enter the username (e.g. bob)
Ensure that User Enabled is turned on
Click Save
See Creating a New User
Create new roles
Click on the Roles link
Click on Add Role
Add the following roles: bank_teller, account_owner and user
Again, do not associate your user with the roles. For our purposes, this is not needed.
See Roles
Create a client
Click on the Clients link
Click on Create
Enter bank-api for the Client ID
For the Root URL enter http://127.0.0.1:8080/bank-api
Click on Save
Ensure that Client Protocol is openid-connect
Change the Access Type to confidential
Change Authorization Enabled to On
Scroll down and hit Save. A new Authorization tab should appear at the top.
Click on the Authorization tab and then Settings
Ensure that the Decision Strategy is set to Unanimous
This is the resource server's Decision Strategy
See:
Creating a Client Application
Enabling Authorization Services
Create Custom Scopes
Click on the Authorization tab
Click on Authorization Scopes > Create to bring up Add Scope page
Enter account:view in the name and hit enter.
Create "View Account Resource"
Click on Authorization link above
Click on Resources
Click on Create
Enter View Account Resource for both the Name and Display name
Enter account/{id} for the URI
Enter account:view in the Scopes textbox
Click Save
See Creating Resources
Create your policies
Again under the Authorization tab, click on Policies
Select Role from the the Create Policy dropdown
In the Name section, type Only Bank Teller and Account Owner Policy
Under Realm Roles select both the bank_teller and account_owner role
Ensure that Logic is set to Positive
Click Save
Click on the Policies link
Select Role again from the Create Policy dropdown.
This time use Only Account Owner Policy for the Name
Under Realm Roles select account_owner
Ensure that Logic is set to Positive
Click Save
Click on the Policies link at the top, you should now see your newly created policies.
See Role-Based Policy
Do note that Keycloak has much more powerful policies. See Managing Policies
Create Resource-Based Permission
Again under the Authorization tab, click on Permissions
Select Resource-Based
Type View Account Resource Permission for the Name
Under Resources type View Account Resource Permission
Under Apply Policy select Only Bank Teller and Account Owner Policy
Ensure that the Decision Strategy is set to Unanimous
Click Save
See Create Resource-Based Permissions
Phew...
Evaluating the Resource-Based permission
Again under the Authorization tab, select Evaluate
Under User enter bob
Under Roles select user
This is where we will associate our user with our created roles.
Under Resources select View Account Resource and click Add
Click on Evaluate.
Expand the View Account Resource with scopes [account:view] to see the results and you should see DENY.
This makes sense because we only allow two roles access to that resource via the Only Bank Teller and Account Owner Policy. Let's test this to make sure this is true!
Click on the Back link right above the evaluation result
Change bob's role to account_owner and click on Evaluate. You should now see the result as PERMIT. Same deal if you go back and change the role to bank_teller
See Evaluating and Testing Policies
Create Scope-Based Permission
Go back to the Permissions section
Select Scope-Based this time under the Create Permission dropdown.
Under Name, enter View Account Scope Permission
Under Scopes, enter account:view
Under Apply Policy, enter Only Account Owner Policy
Ensure that the Decision Strategy is set to Unanimous
Click Save
See Creating Scope-Based Permissions
Second test run
Evaluating our new changes
Go back to the Authorization section
Click on Evaluate
User should be bob
Roles should be bank_teller
Resources should be View Account Resource and click Add
Click on Evaluate and we should get DENY.
Again this should come as no surprise as the bank_teller has access to the resource but not the scope. Here one permission evaluates to true, and the other to false. Given that the resource server's Decision Strategy is set to Unanimous, the final decision is DENY.
Click on Settings under the Authorization tab, and change the Decision Strategy to Affirmative and go back to steps 1-6 again. This time, the final result should be PERMIT (one permission is true, so final decision is true).
For the sake of completeness, turn the resource server's Decision Strategy back to Unanimous. Again, go back to steps 1 through 6 but this time, set the role as account_owner. This time, the final result is again PERMIT which makes sense, given that the account_owner has access to both the resource and scope.

i know i am bit late to the party but let me try to explain as much as i can.
in keycloak we have terms like :
Resource : object which users will be accessing or performing the action on
Auth scopes : Actions that users can perform on the specific object
Policies : Policy
Permission : Mapping actually occur here
If you don't want to follow manual way you can export this JSON and all the users, resources, permissions will be auto-set bu keycloak
JSON configuration file
Now let's see a scenario where :
Now we have few resources like :
Account
Bot
Report
We want to implement the scenario where only specific user can performe specific actions.
Setting up the Keycloak
Create a new realm
Click on the Add Realm button.
Enter test-v1 as the name.
Click on Create.
Create new roles
Click on the Roles
Click on Add Role
Create the roles "admin", "agent" & "super_admin"
Create a client
Click on the Clients tab
Enter app-client in Client ID textbox
Click on Save
Select and choose client again to configure other settings
Verify the client Protocol is openid-connect
Set Access Type to confidential
Set Authorization Enabled to On
Click on Save button at last.
A new Authorization tab will appear at the top.
Select on the Authorization tab and then Settings
Check that the Decision Strategy is set to Unanimous. This is the resource server strategy
Create Custom Auth Scopes
Go the Authorization tab
Select Authorization Scopes > and click on Create
Enter scopes:create & scopes:view in the text and save values.
Create Resource
Go to Resources tab now > and click on Create
Enter one by one and create the following resources res:account & res:bot & res:report
For all resource in scope text select both scopes that we created early scopes:create & scopes:view
Click Save
Create policies
Again inside the Authorization tab, select on Policies
Click on the Create Policy dropdown and select the Role
In the Name textbox, Admin
In Realm Roles select role Admin
Check Logic is set to Positive
Click Save, Do it same for "Agent" & "Super_admin"
Again inside the Authorization tab, select on Policies
Click on the Create Policy dropdown and select the Aggregated
In the Name textbox, Admin or Super_admin or Agent
In Realm Roles select role Admin & Super_admin & Agent
Check Logic is set to Affirmative
Click Save
Create permission
Again inside the Authorization tab, select on Permission
Click on the Create Permissions dropdown and select the Scope-Based
In the Name textbox, account-create
In resource box, select the "resource res:account"
In scopes select, scopes:create
Apply policy Admin
We have to set permission same way for all the resources as per requirement
Create user
Inside the user tab create one test user
We will not assign any roles, scopes, or group to it for testing
Let's Evaluate
Again inside the Authorization tab, select on Evaluate
Select the client we created, app-client
In user select the created user, test
In roles select the created user, admin
Resource value, res:account
Click on Add button
Click on Evaluate button
You will see grant is permitted as Admin role has access to do operations create and view on resource account.
Let's Evaluate Again
Again inside the Authorization tab, select on Evaluate
Select the client we created, app-client
In user select the created user, test
In roles select the created user, admin
Resource value, res:report
Scopes value, scopes:create
Click on Add button
Click on Evaluate button
You will see grant is Deny as only Super_Admin role has access to do operations create on resource report.

I was looking to enforce authorization via pure HTTP methods, without using the adapter as Lua did not have an adapter. Hope this answer helps people looking for non-adapter based method.
If you are looking for the adapter the quick start guide is the best place to start. Especially the spring boot authz example.
For pure HTTP based implementation:
Step 1:
Define the policies and permission in the Keycloak Admin UI
Step 2
Have an internal mapping of which HTTP paths belong to which resources and the required scopes for each path. This can be also saved in the configuration file. When a particular route is invoked, call the Keycloak token endpoint to validate the claims of the access token.
{
"policy-enforcer": {
"user-managed-access" : {},
"enforcement-mode" : "ENFORCING"
"paths": [
{
"path" : "/someUri/*",
"methods" : [
{
"method": "GET",
"scopes" : ["urn:app.com:scopes:view"]
},
{
"method": "POST",
"scopes" : ["urn:app.com:scopes:create"]
}
]
}
]
}
}
If you are using an adapter and does not specify the path or resource, the adapter will internally search for the paths and resources from Keycloak.
Step 3:
Use the token endpoint to get or evaluate the permissions. You can use response_mode parameter to either obtain the final decision (whether to provide access) or retrieve the entire permissions.
curl -X POST \
http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token \
-H "Authorization: Bearer ${access_token}" \
--data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
--data "permission=Resource A#Scope A"
If the authorization request does not map to any permission, a 403 HTTP status code is returned instead.

A working solution with resources, scopes and permissions can be found here
keycloak-nodejs-example
Just run already configured Keycloak using docker-compose using Quick Start guide.
Other useful examples in the project
Custom login without using Keycloak login page.
Stateless Node.js server without using a session. Keycloak token is stored using cookies.
A centralized middleware to check permissions. Routes are not described explicitly can't be accessed.
Configuration without keycloak.json. It can be used to having configuration for multiple environments. For example — DEV, QA.
Examples of using Keycloak REST API to create users, roles and custom attributes.

Related

Oracle apex not recognizing user roles

So I have the users in a table and I know my login system works because I use it for other workspaces. However across all the applications in this particular workspace I am having an error where users roles are not being recognized in particular I can't even get the admin page to work for me and I am a developer. If anyone has any clue on how to fix this it would be greatly appreciated.
If that first image is the default Admin pages, then wouldn't that mean you have access since you can see that page?
(which by default, if you let APEX create it for you through New Page > Features > Access Control) has Administration Rights set as the Authorization scheme
You have two places to check to find the issue:
Shared Components > Security > Authorization Scheme
Go to or Click your Administation Rights, under Authorization Scheme, you need to make sure you are using Is in Role or Group IF that is the requirement and you are to use the created roles. Make sure the role, Administrator (if default roles exist) is listed.
if validation is once per session, and you're still in the same session. log out and log back in. The problem should go away
Shared Components > Security > Application Access Control
Check under Role Assignments if your username is there.
Click Administrator under Roles, and make sure Administration Rights under Associated Authorization Schemes has the Is in Role or Group as the scheme type
If there is a different Authorization scheme (not Is in Role or Group) or you have different roles, then I would suggest post a new question with more details on your setup.

Is the appropriate way to fetch user roles/permissions/information from an ID Token or an API endpoint (or other)?

When creating an Angular web application that also has a backend API, I feel like there are a few different options when it comes to getting User Info such as roles/permissions/display name/email/etc.
We can use an ID Token to store user claims like this. That token can be put into local storage or a cookie and the Angular app can read it and render the UI/guard against unauthorized route navigation/etc as soon as the app spins up (since the ID token is available right then and there).
We can NOT use an ID Token for this information at all and instead have an API endpoint that we have to call every page re-load to fetch this data. The server would decode our access token/ID token and return the data in JSON format.
Lastly, there could be some hybrid solution where basic User Info like names/emails are stored int he ID token and available right away, but user permissions (which could be a larger payload and maybe not wanted in a token that should be small) could be fetched via an API
Is there maybe a 4th option I didn't think about?
I haven't been able to find many conventions around which of these options is the best. I like the ID token option as it requires no "blocking" of the UI until the API request is done making the page load that much faster, but I'm not sure if that goes against other conventions.
All your approaches rely on a permissions-based system where you would have been granted permissions upon login. These are sometimes referred to as birth rights since they are typically given when the user is created or whenever their permission sets change. The typical way to carry birth rights around is to have them as scopes / assertions inside an identity token (e.g. OAUth 2.0) that you pass along from service to service.
You can also have your applications retrieve additional permissions / roles / entitlements from a backend store (a database for instance) based on the user ID so that you know what your user can or cannot do.
So far this is essentially role-based access control / permissions-based access control.
The main challenge with that approach is role explosion / permissions explosion as well as token bloat (too many permissions in the token) and administration pains - you have to assign roles and permissions to users all the time. You have to deprovision. It becomes a management nightmare and a risk you may have the wrong permissions set for users. You then need to think about identity and access governance as well as recertification. Heavy.
What's the alternative?
You definitely need some roles - yes - but they should be kept to a minimum - essentially the business roles you need in your apps e.g. a doctor, a nurse, a non-medical staff rather than doctor_hospital1_unitA.
You should then express your authorization as plain-old English policies using any number of attributes - not just user attributes but also contextual information (time, location), resource information (what type of object, who owns it, where is it? How sensitive is it?), and action information (view, edit, delete...).
Sample Policies
A doctor can view a medical record if they are assigned to the patient the medical record belongs to
A nurse can view a medical record if the medical record is in the same unit as the nurse
A non-medical staff can view the financial section of a medical record but not the medical section.
Attribute-Based Access Control
Following this approach is called attribute-based access control (abac). In ABAC, you clearly decouple your app from the authorization process. Authorization is expressed as policies rather than code which makes it easier to:
update
audit
review
How to implement?
You have several options to implement ABAC (from open-source to commercial). You can go down the XACML (xacml) path, the ALFA alfa path, or others. They all have similar architectures with:
the notion of a policy decision point (PDP): a service that evaluates the authorization requests against the set of policies you defined and produce decisions (Permit / Deny) that can be enriched with additional information e.g. order to do two-factor Authentication.
the notion of a policy enforcement point (PEP): an interceptor that sits in front of or inside your API that will send an authorization request to the PDP.
I've written about the architecture more in detail in this SO post.
ALFA Example
In ALFA, a sample policy would look like:
policyset viewMedicalRecord{
target clause object == "medical record" and action == "view"
apply firstApplicable
policy allowDoctors{
target clause role == "doctor"
apply firstApplicable
rule allowAssignedPatient{
permit
condition patient.assignedDoctor == user.name
}
}
}

Is claims based authorization appropriate for individual resources

I understand the usage of claims for things I would commonly refer to as "roles" or "permissions". I know that claims are more general, but from what I have seen in practice, it usually boils down to this: If user has this set of claims they can access certain areas, or perform certain functions.
Imagine a wiki application. You might have a content_contributor claim that would allow a user to add content, a content_admin claim that would allow a user to remove content, and a modify_user claim that would allow the granting of contributor rights to other user.
Taking this example a step farther, I may want to restrict users so that they can only see content created by themselves or their team.
If a user can only see content created by themselves, would we have a claim for each piece of content they created, or would we delegate that authorization to the application?
When you are talking about roles and permissions then you are talking about authorization.
Claims are typically not for authorization. (Identity)Claims are there to model the identity of the user: who is the user? The claims on itself do not tell anything about authorization. A user can have a role claim, but this doesn't tell the application what the user is allowed to do.
Authorization is done by the application, based on who the user is. Think of authorization as a set of rules, like:
18+: allow when user is older than 18 (DateOfBirth).
Use car: allow when user has a drivers license.
Or something like that.
Roles are a bit confusing, as they are often misused for authorization. Please read this article for some background information.
The problem with roles IMO is that these are not universal. I can be a Doctor in one hospital, while I'm a Patient in another. And I can be Admin for one tenant, but a User for another tenant. So they have only meaning within a certain context.
The only reason to include roles as claim is that you won't need to lookup this information as it is already present. But given the previous remark, you actually can't include this information. And it will only give you headaches when you do. Because you can't do simple things like update or change permissions or profile settings, until the user logs in again.
So as a rule of thumb: keep authorization close to the resource (api / website). Because that is the place where the business rules are implemented. And that's the place where you can store and update permissions, etc.
Keep a seperation of concerns when it comes to authentication and authorization. Authentication tells you who the user is, and authorization tells you what the user is allowed to do. Don't mix these two.
Translating this to your wiki application:
Create a seperate context where you store authorization information like roles and permissions. You can manage this in a central resource (for multiple applications) or use the context in your application. I would not mix this context with the business context.
Add a user in the authorization context and add a role content_contributor. Within the application read the permissions (from the central API, the local authorization context, a settings file, or anything that suits best) for that user (based on the sub claim). Cache it to speed up performance, and apply the rules to determine whether the user is allowed to access the resource.
You can extend this with resource-based authorization. Save the value of the sub claim in the content record to identify the owner. When the current user matches the sub claim value, then the current user is the owner.
You can use the same approach for teams. Add a teams table to the business context and link the user to one or more teams. Directly using the sub claim value or indirectly, using a Users table, also in the business context, where the user is linked to the sub claim value. You can add name, etc. in case you want to show this information (like in a report).
You can save team id and / or user id or sub claim value (owner is member of the same team as current user) in the content record in order to determine the allowed access for the user.
My setup would be like this:
Identity context: users + userclaims. For authentication only. Application independent.
Authorization context: users (id = sub claim) + per application: roles, permissions, etc. In seperate 'local' databases or in a central database. For authorization only.
Business context: users (Id, Name, 'foreign key' sub claim, without the actual database relation as the table is outside the context) + teams, profile, settings, etc. Linked to the sub claim value when users table is omitted.
In order to keep the users table in the business context up-to-date, periodically refresh the values. You can for instance update values when the user logs in after x time. Or once in a while query the Identity Context (using the API) to request user information (using the identities User Info endpoint).
In all contexts there can be a users table, but they all have a different meaning and contain other information. So there is no redundant information.
Authorization takes place inside the application and is based on the business rules (policies) and authorization information from the authorization context.
As a final remark, when the current system requires role claims (like for User.IsInRole() or [Authorize("role")]) then you can read (from cache) the role / permissions on each call and add these to the claims collection of the current user (claims transformation).

Setting up a restricted user group in MODX

I am working with a lot of MODX since 2010. From time to time i coudl need another user group with restricted permissions. Like "Can edit content, but not change settings". So the user can't break anything which is relevant for die CMS itself.
I added users, placed them into roles and groups, but somehow it never works the way I expect it to work. A role is not a "role" but a level of authority. A group is just a link to a set of permissions, which is already setup as a ruleset. Still, if I create and setup the group "content editor", I never get it running as expected.
Is there a guide (or even an extra?) to setup restricted user account without breaking ones brain?
There's a basic tutorial available in the official documentation: https://docs.modx.com/revolution/2.x/administering-your-site/security/security-tutorials/giving-a-user-manager-access
My personal recommendation would be to ignore roles altogether. Whenever you need to enter a role (when adding a policy to a user group, or when adding a user group to a user) just pick "Super User - 0". They're an added complexity to allow, essentially, different permissions within the same user group, that 99% of the people don't need.
The primary thing to do is to create a policy, based on the "Administrator" policy set, that contains the permissions you want the user to have in the manager. Those would include the relevant resource/document permissions, but not settings, for example.
Then you add that policy to the user group of your choice as a "mgr" context policy.
The usergroup will also need context permission to be able of interacting with specific contexts. So on the contexts tab in permissions, add the different contexts you want, with the contexts policy.
As #optimuscrime commented, ACLs can be a little complicated, but that's the general approach.

Authorization in GraphQL servers

How to handle Authorization in GraphQL servers?
Shall I pass the JWT token in the Authentication header of every requests and check for the authorized user after resolve() and check for the role of user on every query and mutation
Introduction
First of all, a common approach for authentication as you state is using a signed JWT that contains the id of the user making the request.
Now let's have a look at the different parameters we can use when considering the authorization of a given request.
who is making the request?
determined by the user id mentioned above. More information about the requester like associated user roles can be looked up in the database. This means that we need to maintain a User table if we are using SQL for example, and add new users to this table on registration.
which operation should be executed?
users might be granted read-only access. Certain mutations or queries are only allowed for certain users.
which fields are included in the query/mutation response?
some fields should be only accessed by certain users.
Permissions
With this information in mind, we can come up with different permission systems. Most commonly, in such a system, no operation is allowed by default. When a request comes in, the parameters mentioned above can be matched with the existing permissions and if a matching permission is found, the request is granted.
Role-based permissions
In certain applications, a role-based approach works great.
For example, for a simpler version of Stack Overflow, we could have the roles EVERYONE, AUTHENTICATED and MODERATOR. A sensible permission rule could be this:
EVERYONE can read questions/answers
requester: doesn't matter (everyone)
operations: allQuestions, allAnswers queries
fields: text
Other rules (leaving parameters out):
* AUTHENTICATED users can create new questions/answers
* MODERATOR users can create new questions/answers
* MODERATOR users can delete questions/answers.
Now for example, if a non-authenticated requests comes in that asks for the allQuestions query, that's fine as we find a permission that allows it (the first).
If on the other hand an authenticated requests comes in for a user that doesn't have the MODERATOR role and includes the deleteQuestion mutation, there is no permission to be found for these parameters. So the request is rejected.
Graph permissions
While role-based permissions represent a solid permission system already, they are not suited at all if we want to make granting permission dependant on things like the relation between the requester and the requested node. In our example, it would be quite the work to add the simple rule that any user is allowed to delete their own questions/answers.
At Graphcool, we have come up with a powerful yet rather simple approach that we call graph permissions to tackle this issue. Let's make the following additional parameters available when checking permissions:
which node is about to be accessed or modified?
determined by a node id
Then we can express permissions using a GraphQL query against a special permission schema to grant or reject permissions on a node level. Access to a given node is only given, if the permission query contains at least one leaf-node that is not null.
In our case, we could specify this permission query:
query {
allAnswers(filter:{
authorId: $userId,
id: $nodeId
}) {
id
}
}
For a given node and user specified by GraphQL variables $userId and $nodeId, we use a query argument filter to either return an empty list if the node wasn't created by the current user, or something non-null otherwise.