The administration and delivery of health care services is the responsibility of each province or territory, guided by the provisions of the Canada Health Act. The provinces and territories fund these services with assistance from the federal government in the form of fiscal transfers.
Clicking on one of the images below will take you to a secure form which you can use to send a custom message for a loved one who is a patient at a Covenant Health hospital. In addition to the message, you will be asked to enter your loved one’s name, the name of the Covenant Health hospital where he or she is receiving care, the patient’s room number, and your name.
Please note: The recipient of the card must be a patient at the Covenant Health facility that you specify. You may send your card at any time, but delivery times are Monday through Friday, 8 a.m. – 4 p.m. If the recipient has been discharged from the hospital, the card will not be delivered. The content of your card is not confidential and will be visible to staff as part of the printing and delivery process.
Draft implementation guide authored with input from technology and lab vendors; created in conjunction with four independent software implementations.
To propose changes, please use GitHub Issues or create a Pull Request.
This implementation guide provides a framework for 'Health Cards', with a short term goal to enable a consumer to receive COVID-19 Immunization or lab results and present these results to another party in a verifiable manner. Key use cases include conveying point-in-time infection status for return-to-workplace and travel. This approach should also support documentation of immunization status and other health details.
Because we must ensure end-user privacy and because Health Cards must work across organizational and jurisdictional boundaries, we are building on international open standards and decentralized infrastructure.
We enable Health Cards by defining building blocks that can be used across healthcare. The core building block allows us to aggregate data into meaningful sets, signed by an issuer, and stored/presented by a consumer as needed. The broader set of use cases might eventually include:
Despite this broad scope, our short-term definition of success requires that we:
Sometimes it's easiest to learn by seeing. For an end-to-end demonstration including Mobile Wallet, Lab API, and Verifier, see c19.cards (source code on GitHub -- and if you want to learn how to test your own components against the demo site, see README.md).
This section outlines higher-level design considerations. See 'Protocol Details' below for technical details.
Each step in the flow must have well-defined inputs and outputs. For each step we define at least one required data transfer method to establish a basis for interoperability.
form_post
flow$HealthWallet.connect
operation to begin the OIDC redirectform_post
flow (assumes devices are online)Which issuers can participate, which test results should be considered, and how do verifiers learn this information?
At a pilot project level:
.well-known
DID URLsIn a post-pilot deployment: a network of participants would define and agree to a formal Trust Framework. This is still TBD.
It is an explicit design goal to let the holder only disclose a minimum amount of information to a verifier. The information required to be disclosed is use-case dependent, and -- particularly in a healthcare setting -- it can be difficult for lay people to judge which data elements are necessary to be shared.
To start, the granularity of information disclosure will be at the level of an entire credential (i.e., a user can select 'which cards' to share from a Health Wallet, and each card is shared wholesale). The credentials are designed to only include the minimum information necessary for a given use case.
If we identify optional data elements for a given use case, we might incorporate them into credentials by including a cryptographic hash of their values instead of embedding values directly. Longer term we can provide more granular options using techniques like zero-knowledge proofs, or by allowing a trusted intermediary to sumamrize results in a just-in-time fashion.
The credential's data is represented in FHIR as outlined in Modeling Verifiable Credentials in FHIR
In this step, the user installs a standards-based mobile app. The app generates a decentralized identifier on behalf of the user, including:
JsonWebKey2020
to enable verification of JWT signatures created by this issuer, using the 'alg': 'ES256'
signature algorithmJsonWebKey2020
to enable encryption of JWE payloads created for this issuer, using the 'alg': 'ECDH-ES'
and 'enc': 'A256GCM'
encryption algorithmSignature and encryption algorithms
There are different cryptographic algorithms, with trade-offs. It's useful to pick algorithms for consistent implementations -- so we're starting with ES256
for verification and ECDH-ES
+ A256GCM
for encryption, but should continue to evaluate this choice as requirements emerge.
This identifier conforms to the did:ion
method. The did:ion
method is an implementation of the Sidetree specification: a spec for DID methods using distributed ledgers.
ION DIDs will be used to secure interactions with the issuer and the verifier, from here on out.
DID Methods
There are different DID methods, with trade-offs. It's useful to pick an approach that:
So we're starting with did:ion
, but should continue to evaluate this choice as requirements emerge.
Long-form vs. Short-form DIDs
did:ion
, a Sidetree-compliant DID method, supports both long and short form DIDs. In brief, a long-form DID can be resolved to a DID Document on its own: it does not require a blockchain query to provide informationabout the public key information state of an identity. A short-form DID requires a blockchain query to resolve a DID Document and requires that the corresponding long-form DIDbe persisted to the blockchain before the short-form DID is resolvable.
As such, communicating via short-form DIDs requires more capabilities/infrastructure: namely integrating with a Sidetree node to resolve these short-form DIDs.However, this infrastructure enables a more robust security model. You need to persist a DID Document in the blockchain to resolve a short-form DID, persisting a DID Document in the blockchain enables a DID to be updated via key revocation, key addition, etc.
Check out the documentation on DID URI Composition and DID Resolution for more details.
This implementation guide recommends using strictly long-form ION DIDs at this time.
In this step, the lab learns about the end-user's DID. To accomplish this, the lab initiates an OpenID Connect request associated with the user's account (e.g., by displaying a link or a QR code in the portal, or by hosting a FHIR API endpoint that allows a third-party app to initiate an OIDC request). The specific OpenID Connect profile we use is called 'DID SIOP'.
Discovering DIDs for labs
To ensure that all parties can maintain an up-to-date list of DIDs for known labs, each lab hosts a /.well-known/did-configuration.json
file on the same domain as .registration.client_uri
lives on, so parties such as the Health Wallet app can maintain a list of DIDs for each domain.
The lab constructs an OIDC request, which is displayed to the user (newlines and spaces added for clarity):
By using this URI-based approach, the lab can choose to display a static QR code printed on a sticker at the check-in counter, generating the signed request objects dynamically each time a client dereferences the request_uri
.
Simplifying the workflow when a FHIR API connection exists
A SMART on FHIR Server can advertise support for issuing VCs according to this specification by adding the health-cards
capability and the __HealthWallet.*
scope to its .well-known/smart-configuration
JSON file. For example:
If the Health Wallet app already has a FHIR API connection to the issuer that includes the __HealthWallet.*
scope, the app can begin an OIDC connection by invoking the $HealthWallet.connect
operation:
The operation returns a FHIR Parameters
resource with the OIDC request URL:
This allows the Health Wallet to begin the connection workflow directly, without requiring the user to sign into the lab portal or take any extra steps. This is an optional entry point for the connection workflow; it does not change the subsequent steps.
The <<URL where request object can be found>>
in request_uri
can be dereferened to a DID SIOP Request. This is a signed JWT that will have a DID as its kid
.
With a header like:
And a payload like:
The id_token_encrypted_response_*
parameters are optional and, if present, signal that the response to this request should be encrypted, not just signed.
response_mode
: the Health Wallet should recognize and support form_post
and fragment
modes.response_context
of wallet
allows the relying party to indicate that the wallet can issue a response in its own user agent context, effectively performing a 'headless' submission and keeping the user in the wallet at the end of the interaction rather than redirecting back to the relying party.Note: The
wallet
response context is only suitable in combination with a SMART on FHIR or other authenticated API connection, to prevent session fixation attacks. Otherwise, the relying party must receive its response in the system browser context, and must verify that the session where the request was generated and the session where the response was provided are both sessions for the same end-user.
In addition to the regular DID SIOP request validation, the Health Wallet retrieves the well-known configuration from the domain corresponding to registration.client_uri
and verifies that the kid
in the request header is a DID associated with the domain.
Bug in spec: Do NOT attempt to validate according to OIDC Core 7.5 because this applies to the response, not the request.
The Health Wallet displays a message to the user asking something like 'Connect to lab.example.com?' (based on the registration.client_uri
value). If the user agrees, the Health Wallet constructs a DID SIOP Response object with a header like:
And a payload like:
The response is signed as a JWS with the user's DID and optionally encrypted using the lab's DID (if the request specified id_token_encrypted_response_*
).The latter step requires looking inside the DID Document for an encryption key, which can be used for encrypting a payload for this party.
TODO: Show the header for the JWE around it
Finally, the Health Wallet submits the id_token
and state
values back to the client's URL (conveyed in the client_id
request field). If response_context
is wallet
, the Health Wallet may issue an HTTP call directly to the client's URL. Otherwise, the Health Wallet submits a response in the context of the system browser. For example, if response_mode
is form_post
and response_context
is wallet
, the response might be sumitted as:
Authorizing FHIR Operations
If the Health Wallet received the openid
link via the FHIR $HealthWallet.connect
operation, the DID SIOP is authorized by including the SMART on FHIR bearer token in an Authorization
header.
When the lab performs tests and the results come in, the lab creates a FHIR payload and a corresponding VC.
See Modeling Verifiable Credentials in FHIR for details. The overall VC structure looks like the following:
VCs look different when represented as JWTs
The example below shows a VC using the 'vanilla' JSON representation. When packaging a VC into a JSON Web Token payload, there are a few differences, to retain compatibility with standard JWT claims. For example, compare this 'vanilla' JSON representation with its corresponding JWT payload. Note that in the JWT payload, most properties have been pushed into a .vc
claim.
In this step, the user learns that new lab results are available (e.g., by receiving a text message or email notification). To facilitate this workflow, the lab can include a link to help the user download the credentials directly, e.g., from at a login-protected page in the Lab's patient portal. The file should be served with a .fhir-backed-vc
file extension, so the Health Wallet app can be configured to recognize this extension. Contents should be a JSON object containing an array of Verifiable Credential JWTs:
Finally, the Health Wallet asks the user if they want to save any/all of the supplied credentials.
Requesting VCs through the FHIR API
The file download is the lowest common denominator. For a more seamless user experience when FHIR API connections are already in place, results may also be conveyed through a FHIR API $HealthWallet.issueVc
operation defined here.
FHIR API Example Approach
$HealthWallet.issueVc
OperationA Health Wallet can POST /Patient/:id/$HealthWallet.issueVc
to a FHIR-enabled issuer to request the generation of a specific type of Health Card. The body of the POST looks like:
The credentialType
and presentationContext
parameters are both required. By default, the issuer will decide which identity claims to include based on the requested presentationContext
. If the Health Wallet wants to fine-tune identity claims in the generated credentials, it can provide an explicit list of one or more includeIdentityClaim
s, which will limit the claims included in the VC. For example, to request that only name be included:
If no encryptForKeyId
parameter is supplied, then the signed VC is returned unencrypted. To request encryption, the client includes an encryptForKeyId
parameter with a valueString
, indicating the requested encryption key ID, starting with #
. This ensures that even if the client's DID document includes more than one encryption key, the server will know which one to use for encrypting this payload.
The response is a Parameters
resource that includes one more more verifiableCredential
values like:
If a client calls $HealthWallet.issueVc
when no DID has been bound to the Patient record, the server responds with a FHIR OperationOutcome
including the 'no-did-bound' code:
In this step, the verifier asks the user to share a COVID-19 result. The overall flow is similar to 'Connect Health Wallet to lab account' above, in that it follows the DID SIOP protocol.
This step can happen in person or online.
The process begins with a QR code or openid://
link. The only differences are:
The SIOP Request Object includes a claims
object asking for relevant Verifiable Credentials to be included in the response:
Based on the requested claims, the Health Wallet prompts the user to share specific verifiable credentials (in the example above: Health Cards). The selected credentials are packaged into a Verifiable Presentation according to W3C Verifiable Presentations.
The id_token
constituting the DID SIOP Response includes a .vp.verifiableCredential
array:
We should be able to specify additional 'return paths' in the DID SIOP workflow that don't depend on an HTTP upload but instead rely on local transfer (e.g., via NFC or bluetooth)
While it's hard to provide the same level of functionality and convenience without a mobile phone, there are still steps we can take to allow broader use of these verifiable credentials. Here's one possibleS approach to graceful degradation: