Most health apps treat consent as a checkbox at signup. Patients tick "I agree", and from then on every integration, every clinician and every AI assistant reads everything, forever.
That model breaks the moment a patient asks a reasonable question: "Can my cardiologist see my lab results for the next month, but not my mental-health notes?"
FHIR R4 already has the building block for this: the Consent resource. Here is how we model scoped, time-limited, revocable consent with it, and the enforcement traps we hit along the way.
A consent a patient can understand has four parts:
All four map onto Consent.provision:
{
"resourceType": "Consent",
"status": "active",
"scope": {
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/consentscope",
"code": "patient-privacy"
}]
},
"category": [{
"coding": [{ "system": "http://loinc.org", "code": "59284-0" }]
}],
"patient": { "reference": "Patient/123" },
"dateTime": "2026-11-06T10:00:00Z",
"provision": {
"type": "permit",
"period": { "start": "2026-11-06", "end": "2026-12-06" },
"actor": [{
"role": {
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/v3-ParticipationType",
"code": "IRCP"
}]
},
"reference": { "reference": "Practitioner/cardio-42" }
}],
"purpose": [{
"system": "http://terminology.hl7.org/CodeSystem/v3-ActReason",
"code": "TREAT"
}],
"class": [
{ "system": "http://hl7.org/fhir/resource-types", "code": "Observation" },
{ "system": "http://hl7.org/fhir/resource-types", "code": "DiagnosticReport" }
]
}
}
Read it as: Practitioner cardio-42 may read Observations and DiagnosticReports for treatment, from 6 Nov to 6 Dec.
When the patient taps "revoke", set status to inactive and keep the resource. You want the history: who had access, when it started, when it ended. Deleting the Consent destroys the audit trail you will need the first time someone asks "who saw my results in March?"
Storing a Consent resource does nothing on its own. FHIR servers don't enforce consent out of the box. The checks have to live in your access layer, on every read:
GET /Observation?patient=123 must drop resources whose type isn't in provision.class. This is the leak we see most often: single-resource reads are guarded, searches aren't._include and _revinclude. DiagnosticReport can drag in resources the consent doesn't cover. Apply the same filter to included resources.deny provision after the outer permit, and let the deny win.
The technical model is only half of it. Patients need one screen that lists every active connection: who, what, until when, plus a revoke button. If a patient can't see a consent, they didn't meaningfully give it.
We build Anpheros, a patient-owned health record on FHIR R4 where every app and clinician access goes through a scoped, time-limited consent like the one above. If you want to experiment with the pattern, there's a free FHIR sandbox with synthetic patients at developers.anpheros.com.
How are you handling consent in your health app: checkbox, scopes, or something in between?