JavaScript client / Production checklist

Production checklist

The demo is a demo: it accepts any health app, matches no patients, and keeps nothing. This page lists what changes when real patients and real charts are involved. Most of it is yours to decide, because it is deployment policy, not protocol.

Key custody

Each check-in encrypts the response to a key that your page creates for that one request and throws away afterwards. The key lives in the page's memory for the few seconds the exchange takes. That is the intended design, not a shortcut, for two reasons.

First, the page is supposed to read the response. Prefilling a form, showing the patient what came back, asking only for what is missing — none of that is possible if the response is decrypted on a server the page cannot see into.

Second, it keeps the library to one implementation. Because the whole flow runs in the browser, nobody has to write and maintain a server-side version in Java, .NET, Python, or Ruby for each EHR backend. The browser is the one platform every deployment has.

What the key protects is the hop from the health app to this page. The response is encrypted to a key only this page holds and is tied to this request and this page's origin, so it cannot be read in transit or replayed at another site. The page was going to read the plaintext anyway, so keeping the key in the page's memory does not widen what the page can see.

The library also supports a server-held key, through the authority option — the authority being the part of the flow that holds the key and opens the response. It is for the narrow case where a deployment does not want the page to hold the response at all: a kiosk you do not control, or a policy that allows PHI to be decrypted only on a server. The cost is real: no prefill in the page, and a service to build and maintain in your own language. Most deployments should not choose it. If yours does, Server-held keys specifies the contract.

Whichever you choose, the ordinary rules for a page that handles health data still apply: serve it over HTTPS, keep third-party scripts you do not trust off it, and treat cross-site scripting on it as the data breach it would be.

Trust policy

The library verifies that a response is internally consistent: the signatures check against the certificate the health app presented, the digests match the data, and the response is bound to your page and your request. It gives you the certificate chain. It does not decide which health apps or which issuers you are willing to believe. The demo accepts any app, including one that vouches for itself; that is fine for a demo and wrong for a chart.

Decide this explicitly, and write it down: which certificate chains you accept, and what you do with a response from an app that only vouches for itself — reject it, or accept it and flag it for review.

Patient identity

Nothing in the library matches a response to a patient record. The context you pass to the FHIR module is written exactly as you gave it. Before you rely on that, the page must be tied to an authenticated patient session. Treat data from an unauthenticated check-in page as data with no known patient attached.

Where the data goes

Data the patient supplied is not the same as data a clinician entered, and that difference should survive wherever the data is written: a staging queue, a reconciliation worklist, a chart section marked for review. Make sure a person can see where each item came from, and that someone is responsible for reviewing it. The Provenance resource the FHIR module writes records the origin; it does not create the review step.

Decide retention as well: how long a raw response is kept in logs or queues, and who can read it there.

Configuration in the URL fragment

The demo keeps its configuration in the URL fragment (the part after #), never in the query string. Fragments are not sent to servers, so patient references and request payloads never appear in server logs or in referrer headers. Keep that property in your own pages. Never accept credentials, tokens, or FHIR authorization material through a URL at all.

Availability and fallback

The Digital Credentials API is not in every browser yet (see Wallets and browser support). The patient may decline. The health app may return nothing useful. Each of those paths has to end at the intake form you already have. A check-in saves the patient typing when it works; if its being unavailable can block a visit, the integration is wrong.

Pin your dependencies

Install from a specific commit rather than a branch, and if you use the hosted module, use the versioned URL (/client/lib/<version>/checkin.js) rather than the one that moves with each release. Then the code you validated is the code you are running. Better still, build and host a copy yourself: this is code that runs on a page where a patient is sharing health data.

Before you go live