Privacy
Query transforms, header allowlist, resource-id hashing.
FHIR requests carry PHI in three obvious places: the query string, the response body, and the response headers. The FHIR extension gives you explicit controls at each boundary — and refuses wildcard configuration so an ergonomic mistake cannot silently commit PHI.
Query transforms
const fhir = instrumentFHIRFetch(fetch, {
run,
baseUrl,
privacy: {
query: {
patient: "hash",
subject: "hash",
identifier: "redact",
},
},
});Three transforms are supported:
preserve— commit the value verbatim (the default when a parameter is not mentioned).hash— commitsha256:<32-hex>— deterministic, dictionary- resistant, disclosure-safe.redact— commit[redacted]— for values that are not worth distinguishing even under hash.
The applied policy is recorded in the receipt event's privacy.query
map — a verifier learns how a value was transformed, not just what
the transformed value looks like.
Hashing is not anonymization. Low-entropy identifiers (short
integers, short strings) may still be brute-forceable. If a parameter's
value space is small, prefer redact.
Header allowlist
Only a small, opt-in list of response headers is ever committed. The default allowlist is:
etaglast-modifiedlocationcontent-location
You can name your own allowlist, but wildcard entries are refused:
// Refused with UNSAFE_HEADER.
privacy: { headers: ["*"] }Authorization headers, cookies, and known-sensitive names are unconditionally blocked even if you try to add them explicitly.
Resource-id hashing
Logical FHIR ids sometimes contain identifiers (patient MRNs, order
numbers). Enable resourceIds: "hash" to swap the committed id with
a short digest:
privacy: { resourceIds: "hash" }The event then carries resource.idCommitment: "sha256:<hex>" in place
of resource.id. The resourceType is always preserved — a verifier
still knows this was a Patient without knowing which one.
What none of this changes
- The FHIR resource body itself, when committed under
embeddedmode, contains whatever the server returned. If you want the body kept out of the receipt, usecommitmentorreferencemode instead — the base recorder API controls that. - The URL you actually sent to the server. Privacy transforms apply to what enters the receipt, not to what leaves your process.