Identity & Access Management (IAM)
Overview
Section titled “Overview”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.”
Core Concepts
Section titled “Core Concepts”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"}Permission
Section titled “Permission”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" }]Policy
Section titled “Policy”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 } ]}Effect
Section titled “Effect”- Allow — grant access
- Deny — block access (always takes priority over Allow)
Condition
Section titled “Condition”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 → AllowUse 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: DenyUse 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 → DenyUse 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}Policy Evaluation Flow
Section titled “Policy Evaluation Flow”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
Evaluation Rules
Section titled “Evaluation Rules”- Explicit Deny beats Allow — if any policy specifies
Deny, it always wins - Default Deny — if no
Allowmatches, access is denied - All Conditions must match — if conditions are present, all must be true
- Audit everything — log every access for traceability
Complex Condition Examples
Section titled “Complex Condition Examples”1. Multiple AND Conditions
Section titled “1. Multiple AND Conditions”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
2. OR Conditions
Section titled “2. OR Conditions”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
3. NOT Condition
Section titled “3. NOT Condition”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.
4. Nested Conditions (AND + OR)
Section titled “4. Nested Conditions (AND + OR)”{ "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)
5. Attribute-Based Conditions
Section titled “5. Attribute-Based Conditions”{ "conditions": { "NumericLessThan": { "resource.priority_score": 50 }, "StringEquals": { "user.department": "SpecialOperations" } }}Example: Only Special Operations staff can manage low-priority-score resources.
6. Data Sensitivity Level
Section titled “6. Data Sensitivity Level”{ "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
Implementation Architecture
Section titled “Implementation Architecture”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
JWT Token Structure
Section titled “JWT Token Structure”{ "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 IDroles— User roles (multiple roles supported)attributes— Additional attributes used in Conditionspermissions— Effective permissions after Policy Engine evaluationjti— JWT ID stored in Redis (stateful JWT)
Best Practices
Section titled “Best Practices”- ✅ Apply Least Privilege — grant only the permissions required for the job, nothing more
- ✅ Use Explicit Deny for sensitive data — high-sensitivity records must have a clear Deny policy
- ✅ Log every access — audit all data access with context and reason where applicable
- ✅ Use Conditions to reduce Role Explosion — prefer conditional policies over creating a new role for every edge case
- ✅ Regularly review Emergency Access — Break-glass access must be reviewed by a Security Officer
- ✅ Use Stateful JWT + Redis — enables immediate token revocation at any time
- ✅ Regular Policy Review — review policies at least annually, or whenever organizational structure changes
Security Considerations
Section titled “Security Considerations”1. Data Masking
Section titled “1. Data Masking”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 }}2. Rate Limiting
Section titled “2. Rate Limiting”Limit API call frequency to prevent data harvesting:
// Example: 100 requests per 15 minutes{ "user_id": "USR001", "rate_limit": { "max_requests": 100, "window": "15m" }}3. Network Geo-Fencing
Section titled “3. Network Geo-Fencing”Restrict access to internal networks:
{ "conditions": { "IpAddress": { "aws:SourceIp": ["192.168.0.0/16", "10.0.0.0/8"] } }}Summary
Section titled “Summary”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.