Skip to content

Identity & Access Management (IAM)

A well-designed IAM system provides:

  • Data protection — only authorized personnel can access sensitive resources
  • Error reduction — prevents accidental access to unauthorized functions
  • Auditability — full record of who did what and when
  • Flexibility — adapts to organizational changes and new roles without rebuilding

The core principle: “Who can do What, under which Conditions.”


Any person or system that needs to access resources.

{
"id": "USR001",
"username": "operator.john",
"full_name": "John Smith",
"employee_id": "EMP2024001",
"department": "Operations",
"email": "john.smith@enterprise.com"
}

A group of similar responsibilities, such as Senior Operator, Staff, or Fulfillment Operator.

{
"id": "ROLE001",
"name": "SeniorOperator",
"display_name": "Senior Operator",
"description": "Credentialed operator with full access to assigned resources"
}

A specific action on a resource, structured as <resource>:<action>.

[
{ "id": "PERM001", "action_key": "resource:read", "description": "Read resource data" },
{ "id": "PERM002", "action_key": "resource:update", "description": "Edit resource data" },
{ "id": "PERM003", "action_key": "order:create", "description": "Create an order" },
{ "id": "PERM004", "action_key": "report:read", "description": "View reports" }
]

A set of rules defining who can do what, under which conditions.

{
"id": "POL001",
"name": "OperatorReadResourcePolicy",
"description": "Allow operators to read resource data",
"statements": [
{
"sid": "AllowReadResource",
"effect": "Allow",
"actions": ["resource:read", "resource:read_history"],
"conditions": null
}
]
}
  • Allow — grant access
  • Deny — block access (always takes priority over Allow)

Additional constraints that must be true for a policy to apply:

  • Ownership — user owns the data
  • Location — user is in a specified department
  • Time — access within an allowed time window
  • Network — request from an allowed IP range
  • Attribute — user or resource attribute matches a value

10 Use Cases: Complex Role & Condition Examples

Section titled “10 Use Cases: Complex Role & Condition Examples”

Use Case 1 — Operator Sees Only Their Assigned Resources

Section titled “Use Case 1 — Operator Sees Only Their Assigned Resources”

Business Requirement: An operator can only view and edit resources they are assigned to manage.

graph LR
    A[John Smith<br/>Senior Operator] -->|assigned to| B[Resource REF001]
    A -->|assigned to| C[Resource REF002]
    A -.->|cannot access| D[Resource REF003<br/>assigned to: Alice Chen]

    style B fill:#90EE90
    style C fill:#90EE90
    style D fill:#FFB6C6

Policy Configuration:

{
"id": "POL_OPERATOR_OWN_RESOURCES",
"name": "OperatorAccessOwnResourcesOnly",
"description": "Operator can only access resources they are assigned to",
"attached_to": { "type": "Role", "id": "ROLE_OPERATOR" },
"statements": [
{
"sid": "AllowReadOwnResources",
"effect": "Allow",
"actions": [
"resource:read",
"resource:read_history",
"resource:update_note",
"order:create",
"report:read",
"attachment:read"
],
"conditions": {
"StringEquals": {
"resource.assigned_operator_id": "${user.id}"
}
}
}
]
}

Evaluation Example:

// Request: GET /api/v1/resources/REF001
// User: operator.john (id: USR001)
const resource = {
reference_number: 'REF001',
assigned_operator_id: 'USR001', // ✅ matches user.id
};
// Condition: resource.assigned_operator_id === user.id
// "USR001" === "USR001" → TRUE → Allow

Use Case 2 — Department Staff Accesses Their Department Only

Section titled “Use Case 2 — Department Staff Accesses Their Department Only”

Business Requirement: Department staff can view and record data for resources in their own department, but cannot access financial data.

graph TD
    A[Staff: Alice Chen<br/>Department: OPS-A] -->|can manage| B[Resource REF001<br/>Current Department: OPS-A]
    A -->|can manage| C[Resource REF002<br/>Current Department: OPS-A]
    A -.->|cannot access| D[Resource REF003<br/>Current Department: TECH-B]
    A -.->|cannot view| E[Financial Data<br/>Billing]

    style B fill:#90EE90
    style C fill:#90EE90
    style D fill:#FFB6C6
    style E fill:#FFB6C6

Policy Configuration:

{
"id": "POL_STAFF_DEPARTMENT_ACCESS",
"name": "StaffAccessDepartmentResourcesOnly",
"description": "Staff accesses resources in their department; billing is denied",
"attached_to": { "type": "Role", "id": "ROLE_STAFF" },
"statements": [
{
"sid": "AllowDepartmentAccess",
"effect": "Allow",
"actions": [
"resource:read",
"resource:read_measurements",
"resource:update_measurements",
"resource:update_notes",
"item:process",
"report:read"
],
"conditions": {
"StringEquals": {
"resource.current_department": "${user.department}"
}
}
},
{
"sid": "DenyFinancialData",
"effect": "Deny",
"actions": ["billing:read", "billing:create", "payment:read"],
"conditions": null
}
]
}

Use Case 3 — Fulfillment Staff Sees Orders, Not Documentation Entries

Section titled “Use Case 3 — Fulfillment Staff Sees Orders, Not Documentation Entries”

Business Requirement: Fulfillment staff must see order requests for all resources to process them, but should not access documentation entries or detailed reports.

graph TD
    A[Fulfillment<br/>Bob Chen] -->|can view| B[Orders: All Resources]
    A -->|can view| C[Restrictions / Contraindications]
    A -.->|cannot view| D[Documentation Entries]
    A -.->|cannot view| E[Reports / Attachments]

    style B fill:#90EE90
    style C fill:#90EE90
    style D fill:#FFB6C6
    style E fill:#FFB6C6

Policy Configuration:

{
"id": "POL_FULFILLMENT_ACCESS",
"name": "FulfillmentLimitedAccess",
"description": "Fulfillment staff sees all orders but not documentation entries",
"attached_to": { "type": "Role", "id": "ROLE_FULFILLMENT" },
"statements": [
{
"sid": "AllowFulfillmentOperations",
"effect": "Allow",
"actions": [
"order:read",
"order:fulfill",
"order:verify",
"resource:read_restrictions",
"item:read",
"item:update_stock"
],
"conditions": null
},
{
"sid": "DenyDocumentationRecords",
"effect": "Deny",
"actions": [
"entry:read",
"report:read",
"attachment:read",
"resource:read_history"
],
"conditions": null
}
]
}

Use Case 4 — Finance Staff Sees Only Financial Data

Section titled “Use Case 4 — Finance Staff Sees Only Financial Data”

Business Requirement: Finance staff needs billing and coverage data but must not access operational or documentation records.

graph LR
    A[Finance Staff<br/>Carol Li] -->|can view| B[Billing Data]
    A -->|can view| C[Coverage / Insurance]
    A -->|can view| D[Payments]
    A -.->|cannot view| E[Operational Records]

    style B fill:#90EE90
    style C fill:#90EE90
    style D fill:#90EE90
    style E fill:#FFB6C6

Policy Configuration:

{
"id": "POL_FINANCE_ACCESS",
"name": "FinanceStaffBillingOnly",
"description": "Finance staff sees only financial data",
"attached_to": { "type": "Role", "id": "ROLE_FINANCE_STAFF" },
"statements": [
{
"sid": "AllowFinancialOperations",
"effect": "Allow",
"actions": [
"billing:read",
"billing:create",
"billing:update",
"payment:read",
"payment:create",
"coverage:read",
"coverage:verify",
"resource:read_basic_info"
],
"conditions": null
},
{
"sid": "DenyOperationalData",
"effect": "Deny",
"actions": [
"resource:read_history",
"entry:read",
"order:read",
"report:read",
"attachment:read",
"measurement:read"
],
"conditions": null
}
]
}

Example of visible data:

{
"resource": {
"reference_number": "REF001",
"full_name": "John Smith", // ✅ visible
"id_number": "ID-12345", // ✅ visible
"coverage_type": "Standard" // ✅ visible
},
"billing": {
"total_amount": 12500,
"paid_amount": 5000,
"outstanding": 7500
},
"operational_records": "***RESTRICTED***" // ❌ denied
}

Use Case 5 — Junior Operator: Restricted from Sensitive Data

Section titled “Use Case 5 — Junior Operator: Restricted from Sensitive Data”

Business Requirement: Junior operators can view general resource data but cannot access highly sensitive classifications (e.g., HIGH or CRITICAL sensitivity records).

graph TD
    A[Junior Operator<br/>Dave Park] -->|can view| B[General Info]
    A -->|can view| C[Standard Classification]
    A -.->|cannot view| D[CRITICAL sensitivity records]
    A -.->|cannot view| E[Restricted data categories]

    style B fill:#90EE90
    style C fill:#90EE90
    style D fill:#FFB6C6
    style E fill:#FFB6C6

Policy Configuration:

{
"id": "POL_JUNIOR_OPERATOR",
"name": "JuniorOperatorLimitedSensitiveData",
"description": "Junior operator cannot access HIGH or CRITICAL sensitivity records",
"attached_to": { "type": "Role", "id": "ROLE_JUNIOR_OPERATOR" },
"statements": [
{
"sid": "AllowBasicAccess",
"effect": "Allow",
"actions": [
"resource:read",
"resource:read_history",
"entry:read",
"order:read",
"report:read",
"measurement:read"
],
"conditions": null
},
{
"sid": "DenySensitiveData",
"effect": "Deny",
"actions": ["report:read", "entry:read", "resource:read_history"],
"conditions": {
"StringEquals": {
"data.sensitivity_level": ["HIGH", "CRITICAL"]
},
"OR": {
"StringLike": {
"data.category": ["RESTRICTED", "CONFIDENTIAL", "PRIVILEGED"]
}
}
}
}
]
}

Example data:

{
"id": "REPORT001",
"test_name": "General Assessment",
"sensitivity_level": "NORMAL", // ✅ visible
"category": "Standard",
"result": "Normal"
}
{
"id": "REPORT002",
"test_name": "Confidential Report",
"sensitivity_level": "CRITICAL", // ❌ Denied
"category": "RESTRICTED",
"result": "***RESTRICTED***"
}

Use Case 6 — Executive: Aggregated Statistics Only

Section titled “Use Case 6 — Executive: Aggregated Statistics Only”

Business Requirement: Executives need dashboards and KPI reports but must not access individual resource records (Privacy by Design).

graph LR
    A[Executive<br/>Director Chen] -->|can view| B[Dashboard / Statistics]
    A -->|can view| C[KPI Reports]
    A -.->|cannot view| D[Individual Resource Records]

    style B fill:#90EE90
    style C fill:#90EE90
    style D fill:#FFB6C6

Policy Configuration:

{
"id": "POL_EXECUTIVE_DASHBOARD",
"name": "ExecutiveDashboardOnly",
"description": "Executive can view aggregated statistics but not individual records",
"attached_to": { "type": "Role", "id": "ROLE_EXECUTIVE" },
"statements": [
{
"sid": "AllowAggregatedData",
"effect": "Allow",
"actions": ["dashboard:read", "report:read", "analytics:read", "kpi:read"],
"conditions": {
"StringEquals": { "data.type": "aggregated" }
}
},
{
"sid": "DenyIndividualRecords",
"effect": "Deny",
"actions": [
"resource:read",
"resource:read_history",
"entry:read",
"order:read",
"report:read"
],
"conditions": {
"StringEquals": { "data.type": "individual" }
}
}
]
}

Example of visible data:

{
"type": "aggregated",
"report": "Monthly Operations Summary",
"data": {
"total_resources_processed": 1250,
"average_processing_time_hours": 4.2,
"throughput_rate": 87.5,
"top_categories": [
{ "code": "CAT-A", "name": "Standard Processing", "count": 230 },
{ "code": "CAT-B", "name": "Extended Processing", "count": 180 }
]
}
}

Use Case 7 — IT Support: Access During Business Hours Only

Section titled “Use Case 7 — IT Support: Access During Business Hours Only”

Business Requirement: IT Support can access systems for troubleshooting, but only during business hours (08:00–18:00) and from the internal network.

graph TD
    A[IT Support<br/>Emma Wilson] -->|08:00-18:00 + internal IP| B[✅ All Systems]
    A -->|outside business hours| C[❌ Denied]
    A -->|external IP| D[❌ Denied]

    style B fill:#90EE90
    style C fill:#FFB6C6
    style D fill:#FFB6C6

Policy Configuration:

{
"id": "POL_IT_SUPPORT_TIME_BASED",
"name": "ITSupportWorkingHoursOnly",
"description": "IT Support access limited to business hours and internal network",
"attached_to": { "type": "Role", "id": "ROLE_IT_SUPPORT" },
"statements": [
{
"sid": "AllowITOperations",
"effect": "Allow",
"actions": [
"system:read_logs",
"system:update_config",
"user:read",
"user:reset_password",
"database:read_metadata"
],
"conditions": {
"DateGreaterThan": { "aws:CurrentTime": "08:00:00" },
"DateLessThan": { "aws:CurrentTime": "18:00:00" },
"IpAddress": {
"aws:SourceIp": ["192.168.1.0/24", "10.0.0.0/16"]
}
}
},
{
"sid": "DenyResourceDataAccess",
"effect": "Deny",
"actions": ["resource:read_history", "entry:read", "order:read", "report:read"],
"conditions": null
}
]
}

Evaluation Examples:

// Request at 14:30 from IP 192.168.1.50
// 1. CurrentTime >= 08:00 → TRUE ✅
// 2. CurrentTime <= 18:00 → TRUE ✅
// 3. SourceIp in 192.168.1.0/24 → TRUE ✅
// Result: Allow
// Request at 20:00 from IP 192.168.1.50
// 1. CurrentTime >= 08:00 → TRUE ✅
// 2. CurrentTime <= 18:00 → FALSE ❌
// Result: Deny

Use Case 8 — Analyst: Anonymized Data Only

Section titled “Use Case 8 — Analyst: Anonymized Data Only”

Business Requirement: Analysts can access data for research and reporting, but only anonymized (de-identified) records.

graph LR
    A[Analyst<br/>Frank Torres] -->|can access| B[Anonymized Data]
    A -.->|cannot access| C[Identifiable Data]

    style B fill:#90EE90
    style C fill:#FFB6C6

Policy Configuration:

{
"id": "POL_ANALYST_ANONYMIZED",
"name": "AnalystAnonymizedDataOnly",
"description": "Analyst can only access anonymized records",
"attached_to": { "type": "Role", "id": "ROLE_ANALYST" },
"statements": [
{
"sid": "AllowAnonymizedDataAccess",
"effect": "Allow",
"actions": ["dataset:read", "dataset:export", "analytics:read"],
"conditions": {
"StringEquals": { "data.is_anonymized": "true" }
}
},
{
"sid": "DenyIdentifiableData",
"effect": "Deny",
"actions": ["resource:read", "dataset:read"],
"conditions": {
"StringEquals": { "data.is_anonymized": "false" }
}
}
]
}

Example anonymized record:

{
"record_id": "DATASET_00123",
"is_anonymized": true,
"data": {
"age_group": "40-50",
"region": "North",
"category_code": "CAT-B",
"category_name": "Extended Processing",
"outcome": "Completed",
"period": "2025-Q2" // quarter only, no exact date
}
}

Fields removed during anonymization:

  • Full name
  • Reference number / ID
  • Exact dates of activity
  • Contact information
  • Location identifiers

Use Case 9 — Consulting Operator: Access Only Requested Resources

Section titled “Use Case 9 — Consulting Operator: Access Only Requested Resources”

Business Requirement: A consulting operator can view a resource’s data only when an active consultation request exists for them.

sequenceDiagram
    participant O1 as John Smith<br/>(Primary Operator)
    participant R as Resource REF001
    participant O2 as Alice Chen<br/>(Consulting Operator)

    O1->>R: Manages resource
    Note over R: Requires specialist review
    O1->>O2: Creates Consultation Request
    activate O2
    O2->>R: Access granted ✅
    O2->>O1: Provides consultation note
    deactivate O2

    Note over O2,R: After consultation closed<br/>access revoked ❌

Policy Configuration:

{
"id": "POL_CONSULTANT_ACCESS",
"name": "ConsultantAccessRequestedOnly",
"description": "Consulting operator accesses resources only via active consultation request",
"attached_to": { "type": "Role", "id": "ROLE_CONSULTANT" },
"statements": [
{
"sid": "AllowConsultationAccess",
"effect": "Allow",
"actions": [
"resource:read",
"resource:read_history",
"entry:read",
"report:read",
"attachment:read",
"review:create_note"
],
"conditions": {
"StringEquals": {
"consultation.consultant_id": "${user.id}",
"consultation.status": "active"
}
}
}
]
}

Consultation Request:

{
"id": "CONSULT_001",
"resource_reference": "REF001",
"requesting_operator_id": "USR001",
"consultant_id": "USR030",
"specialty": "Technical Review",
"status": "active",
"created_at": "2025-10-10T10:00:00Z"
}

Evaluation:

// User: USR030, consultation.consultant_id = USR030, status = "active"
// → Allow
// After closing the consultation:
// consultation.status = "completed" → Condition fails → Deny

Use Case 10 — Emergency Operator: Full Access with Mandatory Audit

Section titled “Use Case 10 — Emergency Operator: Full Access with Mandatory Audit”

Business Requirement: An emergency operator can access all data in urgent situations, but must provide a reason and every action is audited.

graph TD
    A[Emergency Operator<br/>Grace Kim] -->|emergency context| B[Full Access ✅]
    B --> C[Audit Log Written<br/>+ Reason Required]
    C --> D[Reviewed by<br/>Security Officer]

    style B fill:#FFD700
    style C fill:#FFA500
    style D fill:#FF6347

Policy Configuration:

{
"id": "POL_EMERGENCY_BREAK_GLASS",
"name": "EmergencyOperatorBreakGlassAccess",
"description": "Emergency operator has full access in urgent situations with mandatory audit",
"attached_to": { "type": "Role", "id": "ROLE_EMERGENCY_OPERATOR" },
"statements": [
{
"sid": "AllowEmergencyFullAccess",
"effect": "Allow",
"actions": [
"resource:read",
"resource:read_history",
"resource:update",
"entry:read",
"entry:create",
"order:read",
"order:create",
"report:read",
"report:order",
"attachment:read",
"attachment:order",
"measurement:read",
"measurement:update"
],
"conditions": {
"StringEquals": { "context.emergency_access": "true" }
},
"audit_required": true,
"reason_required": true
}
]
}

Emergency Access Request:

{
"user_id": "USR040",
"user_name": "Grace Kim",
"role": "EMERGENCY_OPERATOR",
"resource_reference": "REF999",
"access_time": "2025-10-10T23:45:00Z",
"emergency_access": true,
"reason": "Resource in critical state with unknown history; restrictions check required immediately",
"ip_address": "192.168.10.50",
"location": "Operations Room 3"
}

Audit Log:

{
"id": "AUDIT_LOG_12345",
"event_type": "EMERGENCY_BREAK_GLASS_ACCESS",
"timestamp": "2025-10-10T23:45:00Z",
"user": { "id": "USR040", "name": "Grace Kim", "role": "EMERGENCY_OPERATOR" },
"resource": { "reference": "REF999" },
"actions_performed": [
"resource:read",
"resource:read_history",
"entry:read",
"order:read"
],
"reason": "Resource in critical state with unknown history; restrictions check required immediately",
"review_status": "pending_review",
"reviewed_by": null,
"review_date": null
}

flowchart TD
    Start([User Request]) --> CheckAuth{User<br/>Authenticated?}
    CheckAuth -->|No| Deny1[❌ 401 Unauthorized]
    CheckAuth -->|Yes| GetPolicies[Retrieve All Policies<br/>from User + Roles]

    GetPolicies --> EvalDeny{Explicit Deny<br/>matches?}
    EvalDeny -->|Yes| Deny2[❌ 403 Forbidden<br/>Deny > Allow]
    EvalDeny -->|No| EvalAllow{Allow statement<br/>matches?}

    EvalAllow -->|No| Deny3[❌ 403 Forbidden<br/>No Allow = Deny]
    EvalAllow -->|Yes| CheckCond{Conditions<br/>satisfied?}

    CheckCond -->|No| Deny4[❌ 403 Forbidden<br/>Condition Failed]
    CheckCond -->|Yes| AuditLog[Write Audit Log]
    AuditLog --> Allow[✅ 200 OK<br/>Access Granted]

    style Deny1 fill:#FFB6C6
    style Deny2 fill:#FFB6C6
    style Deny3 fill:#FFB6C6
    style Deny4 fill:#FFB6C6
    style Allow fill:#90EE90
  1. Explicit Deny beats Allow — if any policy specifies Deny, it always wins
  2. Default Deny — if no Allow matches, access is denied
  3. All Conditions must match — if conditions are present, all must be true
  4. Audit everything — log every access for traceability

All conditions must be true:

{
"conditions": {
"StringEquals": {
"resource.current_department": "${user.department}",
"resource.status": "active"
},
"DateGreaterThan": { "aws:CurrentTime": "08:00:00" },
"IpAddress": { "aws:SourceIp": ["192.168.1.0/24"] }
}
}

Example: Staff can access resources only when:

  • Resource is in their department AND
  • Resource is currently active AND
  • Access is within business hours AND
  • Access is from internal network

At least one condition must be true:

{
"conditions": {
"OR": [
{ "StringEquals": { "resource.assigned_operator_id": "${user.id}" } },
{ "StringEquals": { "consultation.consultant_id": "${user.id}" } },
{ "StringEquals": { "user.role": "ROLE_EXECUTIVE" } }
]
}
}

Example: Access is granted if the user is:

  • The assigned operator OR
  • An active consultant OR
  • An executive

Grant access unless the condition matches:

{
"conditions": {
"NOT": {
"StringLike": {
"data.category": ["RESTRICTED", "CONFIDENTIAL", "PRIVILEGED"]
}
}
}
}

Example: Allow access unless the data category is RESTRICTED, CONFIDENTIAL, or PRIVILEGED.


{
"conditions": {
"StringEquals": {
"resource.current_department": "${user.department}"
},
"OR": [
{ "StringEquals": { "user.role": "ROLE_SENIOR_STAFF" } },
{
"DateGreaterThan": { "aws:CurrentTime": "06:00:00" },
"DateLessThan": { "aws:CurrentTime": "22:00:00" }
}
]
}
}

Example: Staff accesses resources only if:

  • Resource is in their department AND
  • (They are Senior Staff OR access is between 06:00–22:00)

{
"conditions": {
"NumericLessThan": { "resource.priority_score": 50 },
"StringEquals": { "user.department": "SpecialOperations" }
}
}

Example: Only Special Operations staff can manage low-priority-score resources.


{
"statements": [
{
"effect": "Allow",
"actions": ["resource:read"],
"conditions": {
"StringNotEquals": {
"data.sensitivity_level": ["HIGH", "CRITICAL"]
}
}
},
{
"effect": "Deny",
"actions": ["resource:read"],
"conditions": {
"StringEquals": {
"data.sensitivity_level": "CRITICAL",
"user.security_clearance": ["LEVEL_1", "LEVEL_2"]
}
}
}
]
}

Result:

  • Allow: data that is not HIGH or CRITICAL
  • Deny: CRITICAL data if security clearance is insufficient

graph TD
    subgraph "Entry Point"
        Web_Client[Web Client] --> Kong[API Gateway Kong]
    end

    subgraph "Service Layers"
        direction LR
        subgraph "ERP Services"
            ERP_Services["Billing BC / Inventory BC<br/>(ERP Bounded Context)"]
            DB_ERP["PostgreSQL<br/>app_erp_db"]
            ERP_Services --> DB_ERP
        end

        subgraph "Security Layer (Central)"
            Auth_Service["Auth Service<br/>(JWT, CSRF)"]
            IAM_Service["IAM Service<br/>(Grant Check)"]
            Redis[(Redis<br/>Session Store)]
            DB_IAM["PostgreSQL<br/>app_iam_db"]

            Auth_Service -- "Checks Session" --> Redis
            Auth_Service --> IAM_Service
            IAM_Service -- "Checks Policies, Permissions, Roles" --> DB_IAM
        end

        subgraph "Core Services"
            Core_Services["Data Owner BC / Data Consumer BC<br/>(Operational Bounded Contexts)"]
            MasterData_Services["MasterData Service"]
            DB_Core["app_core_db<br/>PostgreSQL"]
            DB_Master["app_master_db<br/>PostgreSQL"]
            Core_Services --> DB_Core
            MasterData_Services --> DB_Master
        end
    end

    subgraph "Shared Infrastructure"
        direction LR
        Storage_Service["Storage Service<br/>(MinIO)"]
        Monitoring_Service["Monitoring Service<br/>(Grafana)"]
        CommonModule["Shared Library<br/>@lib/common"]
    end

    Kong -- "1. External API Call" --> Auth_Service
    Auth_Service -- "2. Security OK, Route" --> ERP_Services
    ERP_Services -- "3. Initiate Call w/ Access Token" --> Auth_Service
    Auth_Service -- "4. Token Validated, Forward" --> Core_Services
    ERP_Services -- "Inter Communication (HTTP)" --> Storage_Service
    Core_Services -- "Inter Communication (HTTP)" --> Storage_Service

{
"header": { "alg": "RS256", "typ": "JWT" },
"payload": {
"sub": "USR001",
"username": "operator.john",
"full_name": "John Smith",
"employee_id": "EMP2024001",
"roles": ["ROLE_OPERATOR", "ROLE_SENIOR_OPERATOR"],
"attributes": {
"department": "Operations",
"security_clearance": "LEVEL_3",
"operator_id": "OPR-12345"
},
"permissions": [
"resource:read",
"resource:update_note",
"entry:read",
"entry:create",
"order:create",
"report:read",
"report:order",
"attachment:read",
"attachment:order"
],
"iat": 1728564000,
"exp": 1728650400,
"jti": "jwt_unique_id_12345"
}
}

Field descriptions:

  • sub — User ID
  • roles — User roles (multiple roles supported)
  • attributes — Additional attributes used in Conditions
  • permissions — Effective permissions after Policy Engine evaluation
  • jti — JWT ID stored in Redis (stateful JWT)

  1. ✅ Apply Least Privilege — grant only the permissions required for the job, nothing more
  2. ✅ Use Explicit Deny for sensitive data — high-sensitivity records must have a clear Deny policy
  3. ✅ Log every access — audit all data access with context and reason where applicable
  4. ✅ Use Conditions to reduce Role Explosion — prefer conditional policies over creating a new role for every edge case
  5. ✅ Regularly review Emergency Access — Break-glass access must be reviewed by a Security Officer
  6. ✅ Use Stateful JWT + Redis — enables immediate token revocation at any time
  7. ✅ Regular Policy Review — review policies at least annually, or whenever organizational structure changes

Even with read access, certain fields should be masked by role:

{
"full_access_view": {
"reference_number": "REF001",
"id_number": "ID-12345678", // ✅ visible
"full_name": "John Smith"
},
"finance_staff_view": {
"reference_number": "REF001",
"id_number": "ID-XXXX5678", // 🔒 Masked
"full_name": "J. Smith" // 🔒 Partial mask
}
}

Limit API call frequency to prevent data harvesting:

// Example: 100 requests per 15 minutes
{
"user_id": "USR001",
"rate_limit": {
"max_requests": 100,
"window": "15m"
}
}

Restrict access to internal networks:

{
"conditions": {
"IpAddress": {
"aws:SourceIp": ["192.168.0.0/16", "10.0.0.0/8"]
}
}
}

A well-designed IAM system must be sophisticated enough to handle real-world complexity:

Flexible — supports diverse and complex roles ✅ Secure — protects sensitive data through Conditions and Explicit Deny ✅ Auditable — logs every access ✅ Manageable — uses Policy over proliferating Roles ✅ Adaptable — add new policies without disrupting existing ones

Advanced IAM is a worthwhile investment for any enterprise system managing sensitive operational data.