-
Notifications
You must be signed in to change notification settings - Fork 24
Description
Summary
The g(10) test kit requests patient/-prefixed scopes for non-patient-compartment resources (e.g., patient/Practitioner.read, patient/Organization.read) and validates that the authorization server accepts these scopes, but never verifies that the server actually honors them for direct reads (GET /Practitioner/{id}, GET /Organization/{id}, etc.).
This allows an EHR to pass certification while returning HTTP 403 on direct reads of referenced non-patient-compartment resources — a behavior we have encountered in production with a certified EHR vendor.
What IS tested
| Mechanism | What it covers |
|---|---|
Scope string check (unrestricted_resource_type_access_group.rb) |
Verifies OAuth scope strings mention the resource type |
NON_PATIENT_COMPARTMENT_RESOURCES list (scope_constants.rb) |
Accepts either patient/ or user/ prefixed scopes |
Patient-scoped search (resource_access_test.rb) |
GET /Resource?patient=X — verifies search access |
| US Core inherited tests | Search + reference resolution for must-support elements |
What is NOT tested
- Direct reads (
GET /Practitioner/{id},GET /Organization/{id},GET /Location/{id}, etc.) — nofhir_readcalls exist for any non-patient-compartment resources - The server actually honoring
patient/Practitioner.read(or.rs) for aGETby ID
Why this matters
Patient-facing applications routinely need to resolve references from clinical resources to directory resources. For example, an Observation.performer reference to Practitioner/abc-123 requires either:
- A direct read:
GET /Practitioner/abc-123 - An
_includeon the original search
The US Core Server CapabilityStatement (STU3.1.1) specifies Conformance Expectation SHALL for the read interaction on Practitioner and Organization, with Reference Policy: resolves. Returning 403 on a direct read when the client holds patient/Practitioner.read is inconsistent with this requirement.
While _include is a viable workaround for some use cases, it does not cover all scenarios (e.g., resolving a reference from a previously cached or stored resource). The CapabilityStatement mandates the read interaction precisely for this reason.
Observed behavior in the wild
We integrate with multiple certified EHR vendors. The direct read approach (GET /Practitioner/{id} with a patient/Practitioner.read token) works correctly on ModMed, athenahealth, and Epic. One certified vendor returns HTTP 403, citing patient compartment restrictions — yet passes Inferno certification because no test exercises this code path.
Suggested addition
Add fhir_read test(s) for non-patient-compartment resources listed in NON_PATIENT_COMPARTMENT_RESOURCES when the granted scopes include a read permission for those resource types. For example, after a successful search that returns a referenced Practitioner ID, perform GET /Practitioner/{id} and verify a 200 response.
References
- US Core STU3.1.1 CapabilityStatement — Practitioner, Organization: SHALL support
read - FHIR Patient Compartment Definition: https://build.fhir.org/compartmentdefinition-patient.html
- 45 CFR § 170.315(g)(10)(i)(A) — requires compliance with US Core mandatory capabilities
- SMART App Launch v2.2.0 — scopes specification