Skip to main content

Medication Service — Security Model

Status: populated Owner: TBD Last updated: 2026-04-17 Companion: Service Template · 13 Security

1. Authentication

  • JWT from identity-service. tid (active tenant) claim mandatory.
  • Service-to-service: signed service JWTs (short TTL) from identity-service.
  • Pharmacy portal: same JWT issuance; device binding enforced for offline.

2. Authorization — Scopes & Roles

ScopeDescriptionDefault roles
medication:readRead meds, prescriptionsclinician, nurse, pharmacist, portal-patient (self)
medication:prescribeDraft/sign/discontinueprescriber
mar:recordRecord administrationnurse, prescriber
mar:readView MARclinician, nurse, pharmacist
dispense:readView queue + dispense detailspharmacist, pharmacy-tech
dispense:createExecute dispensepharmacist
dispense:countersignCounter-sign Schedule IIlicensed pharmacist (≠ dispenser)
inventory:readView stockpharmacist, pharmacy-tech, inventory-manager
inventory:writeGRN, adjust stockpharmacy-tech, inventory-manager
inventory:transferTransfer between nodespharmacy-tech, inventory-manager
inventory:recallMark lot recalledpharmacist-in-charge
reconciliation:*Reconciliation sessionsprescriber
medication:cs:prescribeControlled-substance prescribeprescriber + DEA/MoPH license + step-up MFA

3. ABAC — Attribute Gates

AttributeGate
patient.tenantId == jwt.tidAlways (RLS backstop)
prescription.encounterLocationNodeId ∈ jwt.locationScopesFor location-scoped roles
isControlled == true → require jwt.amr includes mfaStep-up authentication
dispense.stockItem.nodeId == user.assignedPharmacyNodeIdPharmacist dispensing scope
counterSign.actor ≠ dispense.actorHard invariant

4. Encryption Classes

DataAt-restIn-transit
Prescriptionstenant-scoped column encryption on sig JSONB (sensitive instructions)TLS 1.3
DispensingEventsStandard Postgres encryptionTLS 1.3
Controlled-substance recordsAdditional AES-256 envelope encryption via KMSTLS 1.3
Drug KB snapshot artifactsSigned SHA-256 hash recorded; blobs on encrypted S3TLS 1.3
Device offline cacheDevice-bound AES-256 using identity-service device keyn/a

5. Audit Events (→ audit-service)

ActionAuditedPHI level
prescription.signAlwaysPHI
prescription.discontinueAlwaysPHI
alert.overrideAlways + override reasonPHI
dispense.completedAlwaysPHI
controlled-substance.dispenseAlways + disclosure-accounting recordsensitive
inventory.recallAlwaysnon-PHI
reconciliation.completeAlwaysPHI
cross-tenant attempt (denied)Alwayssecurity
bulk exportAlwaysPHI

6. GDPR / Data Subject Rights

  • Participates in erasure saga (SUBJ-ERASE): anonymizes patient FKs on prescriptions and dispenses beyond regulatory retention; does not delete rows required for controlled-substance ledger.
  • Participates in export saga (SUBJ-EXPORT): produces MedicationRequest, MedicationDispense, MedicationAdministration, MedicationStatement bundle.

7. Data Residency

  • Afghanistan deployment: primary region me-central-1 (UAE) or local MoPH-approved region; controlled-substance records must not leave national boundary per MoPH data-residency.
  • Per-tenant override via config-service.

8. Rate Limiting

RouteLimit (per actor)
POST /medications/{id}/sign30 rpm
POST /dispenses120 rpm
POST /medications60 rpm

Rate-limit breach: 429 + Retry-After header.

9. Secrets

  • Drug KB credentials, NCPDP SCRIPT certificates, KMS keys stored in Vault.
  • .env.example enumerates vars; src/infrastructure/config/env.ts validates with Zod and fails startup if missing.