Authorization
Authorization is the verification if a subject (someone or something) is allowed to access a resource. It relies on secure authentication to identify the subject.
The way authorization is handled is not standardized by OAuth 2.0 and there are many approaches. OAuth 2.0 offers ways of providing information for the authorization decision via claims in tokens or in the OpenID Connect Userinfo endpoint.
Typical approaches are RBAC (Role Based Access Control) and ABAC (Attribute Based Access Control). RBAC was too rigid for the industrial use cases for which Multitenant Access Control was designed. Therefore, resource-based access control lists were added to the pure RBAC to cater for the huge amounts of resources to be protected in the diverse working environments.
PBAC (Policy Based Access Control) is gaining significant traction since the 2020s and is a strong contender for future authorization concepts supported by Multitenant Access Control building on top of the existing concepts.
Authorization domain model
The authorization domain model offers an overview over the data relevant for authorization decisions for protected resources. It does not cover the authentication domain for log in as that part is covered by the OpenID Connect standard.
The basic concept are roles that have been granted privileges like add or delete on resources. Those roles can be assigned to users, groups and applications to grant them access.
The access control list (ACL) contains the protected resources including the related permissions of the roles (granted privileges).
Tenants form isolated spaces that can be used to model independent organizations. After establishing a relation between each other, organizations can create contracts to share things. They can provide application roles (and thus resources) to other organizations for the other organization’s own purpose and they can grant access to their own application roles and resources.

Access management for requests
Multitenant Access Control uses the concept of access control lists (ACL) to allow applications to authorize a request by a user or application to access protected resources.

The ACL contains the roles and their privileges on resources. It can reach substantial size and may take a while to load, so it should be loaded before being required for incoming resource requests.
The application’s ACL will be the same regardless of the organization used to request it. Typically, the tenant that provides the application to the system is used to load the ACL. See our API documentation on the ACL request for more details.
The applicationId of resources is irrelevant for evaluating an application’s ACL as it matches the application for all resources anyway (exception: the special user ACL which contains static resources of all modules). |
Consider persisting the ACL together with the resources which are managed by the resource server to speed up service restarts. If you persist the ACL in the database, it can be evaluated in the queries on resources for even faster and more efficient authorization decisions.
As the privileges of roles may change over time, it has to be updated regularly. As of now, there is no explicit integration event to trigger an update, so the recommended approach is respecting the cache HTTP headers received when loading the ACL or a simple time based schedule like once every minute, which would be our recommendation.
Some integration events like the creation or deletion of a contract related to the application or the deletion of an organization may be used to trigger an ACL refresh. See our section on integration events for more information.
ACL usage in frontends
For fine-grained access / dynamic resources:
-
Compare the user’s roles with the information available in the application’s ACL already available in the application’s backend.
-
Transfer information from ACL to UI either as part of the resources (e.g., a flag like "canEdit" for each resource) or with a dedicated request to a custom ACL endpoint offered by the application’s backend.
For static resources either use the same approach as for fine-grained access / dynamic resources or the special user ACL which contains the user’s privileges on all static resource of all modules.
For example, if a user wants to read a resource, they must have a role that has read privileges on that resource.
User’s Roles | ACL |
---|---|
|
|
Result: User may read or modify that organization’s morning-shift.
A typical flow from the UI to the backend includes:
-
The backend retrieves and updates its access control list. This should be done periodically and not on request.
-
A user logs in at an identity provider to get a user access token in the UI.
-
The UI takes the received token and calls a backend.
-
The backend takes the token to the introspect endpoint to verify the token and get the users roles.
-
The backend searches for the requested resource in the access control list to check if the user has a role that grants the required access to the resource.
Authorization in performance sensitive scenarios
Fetching a new token (client side) and introspecting a token (server side) for every request is not recommended for performance reasons. Therefore, optimizations should be applied:
Here are the steps that improve performance:
Keep using active tokens in clients
Token are valid for a predefined period of time during which they can be used again and again to request resources. The token response of MACMA contains the expires_in
field that contains the TTL for that token in seconds. It is safe to reuse this token until close to expiration.
If a token is revoked prior to expiration it will be rejected by the resource server on introspection, signaled by a 401 Unauthorized status code. |
Cache introspection result (resource server)
The result of the token introspection can be trusted for a certain period of time depending. MACMA delivers a hint (claim) in the introspect result that recommends a cache time to live for the given token. This is based on the token type and a system-wide configuration by the operator for both token types (see Operations Manual for details).
-
Short caching time hint for user-tokens → quicker response to revocation and role changes, higher latency.
-
Long(er) caching time hint for service-tokens → slower response to revocation and role changes, low latency use-cases.
The claim is riexp
(recommended introspection expiration) similar to the exp
claim for the expiration time of the token, both in unix time (seconds since 1970-01-01T00:00:00Z
).
Prefetching token before expiry
The service may request a new token shortly before the old token expires to avoid failed calls due to time-desync issues between servers and to leave some time for the actual resource request and token introspection by the resource server.
Pre-flight request by client service to (potentially) trigger introspect caching in resource server
In use cases in which even the slightest delay for authorization might jeopardize response time guarantees and it is known that the resource server supports introspection caching, the client service can issue pre-flight requests. That means sending requests for tokens at intervals to keep the target service’s introspection cache up to date.
Continuously preflight-requesting is generally not necessary and only ever recommended after fetching a new token (due to imminent expiry). |
Optimizations to be avoided
Some potential optimizations have severe disadvantages and should therefore be avoided. Here is why we strongly discourage these optimizations:
Trying to refresh introspection cache triggered by the Client Application
How:
Why you should avoid this:
|
Refreshing introspection cache triggered by the Server Application
Having read the previous section one could think: "The server does known the expiry, so let it refresh:" How:
Why you should avoid this:
|