Skip to main content

07 — Authorization Model

Status: ✅ Draft
Prerequisite: 06 — Authentication Flow
Next: 08 — Security Architecture

Detailed design of Core RBAC — role hierarchy, permission model, role assignment rules, /v1/rbac/check evaluation logic, multi-scope and temporal scoping, and the Gathri exception.


1. Permission String Format and Wildcard Behaviour

Confirmed in architecture session — do not revisit.

All permissions follow resource:action notation:

volunteer:approve
volunteer:view
allocation:view
report:export

This is the same convention as AWS IAM (s3:GetObject, ec2:DescribeInstances). The RBAC Engine stores permissions as strings in this format within role definitions.

Wildcard permissions

Wildcard permissions are supported at the action level only.

PatternSupportedMeaning
volunteer:*All actions on the volunteer resource
*:approveNot supported — resource must be explicit
*:*Not supported

Auto-grant implication: a role holding volunteer:* automatically passes any future action added to the volunteer resource without a role update. Wildcard roles are reserved for high-trust, module-admin-level assignments — not general user roles.

Module-side check: modules evaluating permissions locally must match the same wildcard logic as the engine.

function hasPermission(permissions, resource, action) {
return permissions.includes(`${resource}:${action}`)
|| permissions.includes(`${resource}:*`);
}

2. Role Levels

Every role in Core has a level that determines its scope.

LevelScopeExample roles
platformNo Miqaat scope — applies across the entire platformPLATFORM_ADMIN
miqaatScoped to a specific miqaatIdVMS_Coordinator, AMS_Reviewer, Istefadah_Ops

A role at miqaat level is always tied to one Miqaat. The same person can hold the same role in two different Miqaats — these are two separate assignments, each with its own miqaatId.

PLATFORM_ADMIN is the only platform-level role. It is documented separately in 06 — Authentication Flow, Section 7.


3. Role Hierarchy

Pending technical discussion — the design below is a starting position, not a confirmed decision.

The parentRole field exists in the C-010 role schema, so hierarchy is intended. But the exact inheritance direction, evaluation logic, and depth limit must be confirmed in a dedicated RBAC technical session before the engine is built. Do not treat anything in this section as final.

Roles can have a parentRole. The proposed model is that a parent role inherits all permissions of its children — it does not pass permissions down.

Miqaat_Operations_Lead ← parent
└── VMS_Coordinator ← child
└── AMS_Reviewer ← child

Under this model, Miqaat_Operations_Lead would hold all permissions of VMS_Coordinator and AMS_Reviewer combined, plus any defined directly on it. A user assigned Miqaat_Operations_Lead would not need separate child role assignments.

This direction needs to be confirmed. The alternative — children inheriting from parents — is equally valid and changes the assignment model significantly. The technical session must decide:

  • Which direction does inheritance flow?
  • Is inheritance resolved at check time (dynamic) or at assignment time (materialised)?
  • What is the maximum supported hierarchy depth?
  • Can a role have multiple parents?
  • How are circular references prevented?

4. Role Assignment Rules

Pending technical discussion — the questions below must be resolved before the RBAC Engine write path is built.

Confirmed

Every role assignment and revocation fires a Core event — this is confirmed in the Event Catalog:

  • role.assigned (C-025) — modules that gate features on role presence subscribe to this
  • role.revoked (C-026) — all modules consume this to invalidate their local permission cache

Pending confirmation

Who can assign roles? The current assumption is only PLATFORM_ADMIN holders can assign or revoke roles. But the question is whether any delegation is needed — for example, can a Miqaat-level operations lead assign sub-roles within their own scope? This needs to be decided: fully centralised (Platform Admin only) vs limited delegation model.

Multiple roles per Miqaat — is this allowed? Can one itsId hold VMS_Coordinator and AMS_Reviewer simultaneously in the same Miqaat? If yes, the RBAC check merges permissions across all held roles. If no, only one active role per itsId per Miqaat is permitted. This changes the engine's evaluation logic and the assignment validation.

Primary khidmat role enforcement — which engine owns it? HR Bank has a quota check (GET /v1/hr/quota) that checks whether a primary khidmat slot is free. But it is not confirmed whether the RBAC Engine enforces this at assignment time, or whether it is purely an HR Bank and module concern. The boundary needs to be agreed.

Are role assignments always explicit? The current position is yes — no implicit grants from ITS group membership, Gathri, or jamaat. But this must be confirmed: are there any cases where ITS data should automatically trigger a role assignment in Core?


5. /v1/rbac/check Evaluation Logic

Full step-by-step evaluation for a single permission check.

Input:
X-Its-Id: ITS-1234567 (from Identity Bridge)
body.resource: "volunteer"
body.action: "approve"
body.miqaatId: "MQ-1447-KHI"

Step 1 — Load role assignments
Find all roles assigned to ITS-1234567 in MQ-1447-KHI
e.g. ["VMS_Coordinator"]

Step 2 — Check temporal validity
Is each assignment within its valid date range?
(see Section 6 — Temporal Scoping)
Drop any assignments outside their valid window.

Step 3 — Expand permissions (with hierarchy)
For each valid role:
Load the role's own permissions
Walk up parentRole chain, collect ancestor permissions
Merge into one permission set.
e.g. ["volunteer:approve", "volunteer:view", "allocation:view", ...]

Step 4 — Evaluate
Does the merged set contain "volunteer:approve"? → exact match → allowed
Does the merged set contain "volunteer:*"? → wildcard match → allowed
Neither? → denied

Step 5 — Return result
allowed: true → reasonCode: ROLE_GRANTS_ACTION, roleMatched: "VMS_Coordinator"
allowed: false → reasonCode: NO_MATCHING_ROLE

Special reason codes

reasonCodeMeaning
ROLE_GRANTS_ACTIONA role held by this itsId grants this action on this resource
NO_MATCHING_ROLENo role held grants this action
ROLE_SCOPE_MISMATCHA matching role exists but is scoped to a different miqaatId
MIQAAT_CLOSEDThe Miqaat is archived — no permission checks are valid
ROLE_EXPIREDA matching role exists but its temporal window has passed

6. Multi-Scope — Holding Roles Across Multiple Miqaats

A Mumin can hold roles in multiple Miqaats simultaneously. Each assignment is independent.

ITS-1234567
├── VMS_Coordinator in MQ-1447-KHI (Karachi 2026)
└── AMS_Reviewer in MQ-1446-MUM (Mumbai 2025)

Every RBAC check includes miqaatId in the request — the engine only evaluates roles assigned for that specific Miqaat. Roles in other Miqaats are invisible to the check.

GET /v1/rbac/permissions also requires miqaatId — it returns permissions for one Miqaat scope only. If a module serves users across multiple active Miqaats simultaneously, it must fetch and cache permissions per Miqaat.


7. Temporal Scoping

Role assignments can carry optional validity dates:

FieldDescription
validFromThe assignment is not active before this date. Absent = immediately active.
validUntilThe assignment expires after this date. Absent = no expiry.

The RBAC Engine checks validity at evaluation time (Step 2 in Section 5). An assignment outside its valid window is treated as if it does not exist — the check proceeds with the remaining valid roles.

Use cases:

  • A volunteer coordinator role that is only valid during the operational phase of a Miqaat
  • A temporary escalated role granted for a specific task window
  • A role pre-assigned before the Miqaat begins (validFrom in the future)

Cache implication: modules with local permission caches must be aware that a cached permission set can become invalid when a role's validUntil passes — not only on a role.revoked event. Modules should factor the earliest validUntil across all roles into their cache TTL. If any role in the cached set expires before the TTL would naturally clear the cache, the module must re-fetch before that expiry.

⏳ Whether Core pushes a role.expired event at validUntil time (so modules can invalidate proactively) or whether modules are expected to manage this themselves — pending architecture decision.


8. The Gathri Exception

Business session required — details below are the current understanding, not a confirmed decision.

In Dawoodi Bohra Miqaat context, a Gathri is a family unit. For certain Miqaat types (particularly Ashara Mubaraka residential registrations), access and quota are managed at the Gathri level — not purely at the individual itsId level.

What this means for RBAC:

Standard RBAC checks are per-itsId. The Gathri exception arises when a permission or quota applies to the family unit and the individual's eligibility depends on the Gathri's status, not only their own.

Example: a Gathri head registers the family for residential accommodation. The Gathri holds the allocation slot. Individual family members' access to venue entry, meal passes, or scanning is derived from the Gathri's confirmed status — not from individual allocation records.

Current position: the RBAC Engine operates on itsId only. Gathri-level logic is expected to live in the module (AMS, Istefadah Registration) that understands the Gathri structure — not in Core RBAC. Core's role is to answer "can this itsId perform this action?" — not "what Gathri does this itsId belong to and what does that grant?"

However, if eligibility or allocation rules reference Gathri status, the Eligibility Engine's rule families may need a gathri rule type that calls ITS data for family membership. This is a rule configuration concern, not a Core RBAC concern.

The exact boundary — what is Core's responsibility vs the module's — must be confirmed in a dedicated business session covering the Gathri model for the specific Miqaat types where it applies.


9. Open Questions

QuestionBlocked On
Role hierarchy — which direction does inheritance flow? Parent inherits child, or child inherits parent?RBAC technical session
Role hierarchy — resolved at check time (dynamic) or at assignment time (materialised)?RBAC technical session
Role hierarchy — maximum depth, multiple parents, circular reference preventionRBAC technical session
Role assignment — fully centralised (Platform Admin only) or limited delegation allowed?RBAC technical session
Role assignment — can one itsId hold multiple roles in the same Miqaat simultaneously?RBAC technical session
Role assignment — which engine enforces the one-primary-khidmat rule: RBAC or HR Bank?RBAC technical session
Role assignment — are there any cases where ITS group membership implicitly grants a Core role?RBAC technical session + ITS Technical session
Whether Core fires a role.expired event at validUntil timeRBAC technical session
Gathri exception — exact boundary between Core RBAC and module responsibilityBusiness session (Gathri model)
Whether Gathri is a rule family in the Eligibility Engine or a separate conceptBusiness session
Role naming conventions — is there a registry or do module teams propose names freely?Platform Admin design session