Skip to content

CDS Hooks

1.0 Draft

This is the draft of the 1.0 release of the CDS Hooks specification. We are currently working towards a 1.0 release and would love your feedback and proposed changes. Look at our current issue list and get involved!

Overview

The CDS Hooks specification describes the RESTful APIs and interactions between EHRs and CDS Services. All data exchanged through the RESTful APIs MUST BE sent and received as JSON structures, and MUST be transmitted over channels secured using Transport Layer Security (TLS).

Conformance Language

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this specification are to be interpreted as described in RFC2119.

Limitations

This specification has the following limitations.

  • The specification provides options for providing a CDS Service access to the EHR's FHIR resources through use of either prefetch and/or a bearer access token to be presented to the FHIR Server. Decisions regarding which approach to take, and details regarding how the choice is implemented, are left up to the EHR vendor/provider, as architectural considerations will come into play.
  • The specification requires that each CDS Service provider be registered (client_id, key-pair identifier) with the EHR Authorization Server, but does not dictate how registration is accomplished (e.g., dynamic vs. manual).
  • The specification acknowledges that each EHR vendor/provider will need to vet CDS Service providers and suggests that vendors/providers may want to create a "white list" of providers deemed "safe" and/or a "black list" of providers deemed "unsafe." Similarly, an EHR vendor/provider may choose to assess the safety of active links embedded in CDS Hooks Cards returned to the EHR. The specification does not suggest how such vetting is accomplished nor suggest factors to consider, as these judgments are dependent upon each EHR vendor's or provider's existing vetting processes and risk-management policy.

Swagger (Open API Specification)

The CDS Hooks specification is available as an Open API Specification using Swagger. You can download the API specification and view it online via the Swagger Editor.

Discovery

Developers of CDS Services SHALL provide a stable endpoint for allowing EHRs to discover available CDS Services, including information such as the purpose of the CDS Service, when it should be invoked, and any data that is requested to be prefetched.

A CDS Service provider SHALL expose its Discovery endpoint at"

1
{baseURL}/cds-services  

HTTP Request

The discovery endpoint is always available at {baseUrl}/cds-services. For example, if the baseUrl is https://example.com, the EHR would invoke:

GET https://example.com/cds-services

Response

The response to the discovery endpoint is an object containing a list of CDS Services.

Field Description
services array. An array of CDS Services

Each CDS Service is described by the following attributes.

Field Optionality Type Description
hook REQUIRED string The hook this service should be invoked on. See Hook Catalog
title RECOMMENDED string The human-friendly name of this service
description REQUIRED string The description of this service
id REQUIRED string The {id} portion of the URL to this service which is available at
{baseUrl}/cds-services/{id}
prefetch OPTIONAL object An object containing key/value pairs of FHIR queries that this service is requesting that the EHR prefetch and provide on each service call. The key is a string that describes the type of data being requested and the value is a string representing the FHIR query.
See Prefetch Template.

HTTP Status Codes

Code Description
200 OK A successful response

Discovery Example

1
curl "https://example.com/cds-services"

The above command returns JSON structured like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
  "services": [
    {
      "hook": "patient-view",
      "title": "Static CDS Service Example",
      "description": "An example of a CDS Service that returns a static set of cards",
      "id": "static-patient-greeter",
      "prefetch": {
        "patientToGreet": "Patient/{{context.patientId}}"
      }
    },
    {
      "hook": "medication-prescribe",
      "title": "Medication Echo CDS Service",
      "description": "An example of a CDS Service that simply echos the medication being prescribed",
      "id": "medication-echo",
      "prefetch": {
        "patient": "Patient/{{context.patientId}}",
        "medications": "MedicationOrder?patient={{context.patientId}}"
      }
    }
  ]
}

Calling a CDS Service

HTTP Request

An EHR calls a CDS service by POSTing a JSON document to the service endpoint, which can be constructed from the CDS Service base URL and an individual service id as {baseUrl}/cds-services/{service.id}. The CDS Hook call includes a JSON POST body with the following input fields:

Field Optionality Type Description
hook REQUIRED string The hook that triggered this CDS Service call
(todo: link to hook documentation)
hookInstance REQUIRED string A UUID for this particular hook call (see more information below)
fhirServer OPTIONAL URL The base URL EHR's FHIR server. If fhirAuthorization is provided, this field is REQUIRED. The scheme should be https
fhirAuthorization OPTIONAL object A structure holding an OAuth 2.0 bearer access token granting the CDS Service access to FHIR resources, along with supplemental information relating to the token. See the FHIR Resource Access section for more information.
user REQUIRED string The FHIR resource type + id representing the current user.
The type is one of: Practitioner, Patient, or RelatedPerson.
For example, Practitioner/123
context REQUIRED object Hook-specific contextual data that the CDS service will need.
For example, with the medication-prescribe hook this will include MedicationOrder being prescribed. For details, see the Hooks specification.
prefetch OPTIONAL object The FHIR data that was prefetched by the EHR (see more information below)

hookInstance

While working in the EHR, a user can perform multiple actions in series or in parallel. For example, a clinician might prescribe two drugs in a row; each prescription action would be assigned a unique hookInstance. This allows a CDS Service to uniquely identify each hook invocation.

Note: the hookInstance is globally unique and should contain enough entropy to be un-guessable.

Example

1
2
3
4
5
curl
  -X POST \
  -H 'Content-type: application/json' \
  --data @hook-details-see-example-below
  "https://example.com/cds-services/static-patient-greeter"
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
   "hookInstance" : "d1577c69-dfbe-44ad-ba6d-3e05e953b2ea",
   "fhirServer" : "http://hooks.smarthealthit.org:9080",
   "hook" : "patient-view",
   "fhirAuthorization" : {
     "access_token" : "some-opaque-fhir-access-token",
     "token_type" : "Bearer",
     "expires_in" : 300,
     "scope" : "patient/Patient.read patient/Observation.read",
     "subject" : "cds-service4"
   },
   "user" : "Practitioner/example",
   "context" : {
       "patientId" : "1288992",
       "encounterId" : "89284"
   },
   "prefetch" : {
      "patientToGreet" : {
         "resourceType" : "Patient",
         "gender" : "male",
         "birthDate" : "1925-12-23",
         "id" : "1288992",
         "active" : true
      }
   }
}

Providing FHIR Resources to a CDS Service

Each CDS Service will require specific FHIR resources in order to compute the recommendations the EHR requests. If real-world performance were no issue, an EHR could launch a CDS Service passing only context data, and the CDS Service could then request authorization for FHIR resources as they were needed, and then retrieve the resources from the EHR's FHIR server. However, CDS Services must respond quickly (on the order of 500 ms.), and so we provide performance enhancements that allow a CDS Service to request and obtain FHIR resources more efficiently. Regardless of the method used to provide FHIR resources to a CDS Service, the EHR must assure that clinical data provided to the CDS Service are the most current data available to the EHR user. Decisions based on stale clinical data pose a safety threat to the patient and must be avoided.

Two optional enhancements are provided. First, FHIR resources may be obtained by passing "prefetched" data from the EHR to the CDS Service in the service call. FHIR resources requested in the CDS Service desciption are passed as key-value pairs, with each key matching a key described in the CDS Service description, and each value being a FHIR resource. If data are to be prefetched, the CDS Service registers a set of "prefetch templates" with the EHR, as described in the Prefetch Template section below.

The second enhancement enables the CDS Service to retrieve FHIR resources for itself, but to do so more efficiently than if it were required to request and obtain its own authorization. If the EHR decides to have the CDS Service fetch its own FHIR resources, the EHR obtains and passes directly to the CDS Service a bearer token issued for the CDS Service's use in executing FHIR API calls against the EHR FHIR server to obtain the required resources. Some EHRs may choose to pass prefetched data, along with a bearer token for the CDS Service to use if additional resources are required. Each EHR may decide which approach, or combination, is preferred, based on performance considerations and assessment of attendant security and safety risks. For more detail, see the FHIR Resource Access section below.

Similarly, each EHR will decide what FHIR resources to authorize and to prefetch, based on the CDS Service description's "prefetch" request and on the provider's assessment of the "minimum necessary." The EHR provider and the CDS Service provider will negotiate the set of FHIR resources to be provided, and how these data will be provided, as part of their service agreement.

Prefetch Template

The prefetch template is a dictionary of read and search requests to supply relevant data. In order to allow for prefetch templates that are dependent upon the particular CDS Service request, prefetch tokens or variables may be defined.

Prefetch tokens MUST be delimited by {{ and }}, MUST be named based upon the field they correspond to, and MUST have a primitive value.

The CDS Hooks specification defines just one prefetch token:

Variable Meaning
{{user}} The value of the user field from this CDS Service request (e.g. Practitioner/123)

Individual hooks specify which of their context fields can be used as prefetch tokens. Only root-level fields with a primitive value within the context object are eligible to be used as prefetch tokens.

For instance, given a hook of example-hook with the following context in which the patientId and medicationId fields are both denoted as prefix tokens:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
"context": {
  "patientId": "123",
  "medicationId": "456",
  "medication": {
    "id": "456",
    "code": {
      ... // FHIR CodeableConcept
    }
  }
}

The prefetch tokens defined by this example-hook would be {{context.patientId}} and {{context.medicationId}}. Note that the context.medication.id field is not eligible to be a prefetch token as it is not a root-level field of the context object.

An EHR MAY choose to honor some or all of the desired prefetch templates, and is free to choose the most appropriate source for these data. For example:

  • The EHR may have some of the desired prefetched data already in memory, thereby removing the need for any network call
  • The EHR may compute an efficient set of prefetch templates from multiple CDS Services, thereby reducing the number of network calls to a minimum
  • The EHR may satisfy some of the desired prefetched templates via some internal service or even its own FHIR server
  • The EHR may deny access because the requested resource is outside the user's authorized context.

Regardless of how the EHR satisfies the prefetch templates (if at all), the prefetched data given to the CDS Service MUST BE equivalent to the data the CDS Service would receive if it were making its own call to the EHR FHIR server using the parameterized prefetch template.

The resulting response, which MUST BE rendered in a single page — no "next page" links allowed — is passed along to the CDS Service using the prefetch parameter (see below for a complete example).

The CDS Service MUST NOT receive any prefetch template key that the EHR chooses not to satisfy; in which case the prefetch template key SHOULD NOT be sent. Similarly, if the EHR encounters an error while prefetching any data, the prefetch template key SHOULD NOT be sent to the CDS Service. If the EHR has no data to populate a template prefetch key, the prefetch template key MUST have a value of null. It is the CDS Service's responsibility to check prefetched data against its template to determine what requests were satisfied (if any) and to manually retrieve any additional necessary data. If the CDS Service is unable to obtain required data because it cannot access the FHIR server and the request did not contain the necessary prefetch keys, the service SHALL respond with an HTTP 412 Precondition Failed status code.

Example prefetch templates

1
2
3
4
5
6
7
{
  "prefetch": {
    "p": "Patient/{{context.patientId}}",
    "a1c": "Observation?patient={{context.patientId}}&code=4548-4&_count=1&sort:desc=date",
    "u": "Practitioner/{{user}}"
  }
}

Here is an example prefetch field from a CDS Service discovery endpoint. The goal is to know, at call time:

Key Description
p Patient demographics
a1c Most recent Hemoglobin A1c reading for this patient
u Information on the current user (Practitioner)

Example prefetch response

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
  "prefetch": {
    "p":{
      "resourceType": "Patient",
      "gender": "male",
      "birthDate": "1974-12-25",
      "...": "<snipped for brevity>"
    },
    "a1c": {
      "resourceType": "Bundle",
      "type": "searchset",
      "entry": [{
        "resource": {
        "resourceType": "Observation",
        "code": {
          "coding": [{
            "system": "http://loinc.org",
            "code": "4548-4",
            "display": "Hemoglobin A1c"
            }]
          },
          "...": "<snipped for brevity>"
        }
      }]
    }
  }
}

The response is augmented to include two prefetch values, where the dictionary keys match the request keys (p and a1c in this case).

Note that the missing u key indicates that either the EHR has decided not to satisfy this particular prefetch template or it was not able to retrieve this prefetched data. The CDS Service is responsible for retrieving this Practitioner data from the FHIR server (if required).

Prefetch query restrictions

To reduce the implementation burden on EHRs that support CDS Services, CDS Hooks recommends that prefetch queries only use a subset of the full functionality available in the FHIR specification. Valid prefetch URLs should only contain:

  • instance level read interactions (for resources with known ids such as Patient and Practitioner)
  • type level search interactions
  • Patient references (e.g. patient={{context.patientId}})
  • token search parameters using equality (e.g. code=4548-4) and optionally the :in modifier (no other modifiers for token parameters)
  • date search parameters on date, dateTime, instant, or Period types only, and using only the prefixes eq, lt, gt, ge, le
  • the _count parameter to limit the number of results returned
  • the _sort parameter to allow for most recent and first queries

FHIR Resource Access

The CDS Service is able to use the EHR's FHIR server to obtain any FHIR resources it requires beyond those provided by the EHR as prefetched data. This is similar to the approach used by SMART on FHIR wherein the SMART app requests and ultimately obtains an access token from the EHR's Authorization server using the SMART launch workflow, as described in SMART App Authorization Guide.

Like SMART on FHIR, CDS Hooks requires that clients present a valid access token to the FHIR server with each API call. Thus, a CDS Service must be able to obtain an access token before communicating with the EHR's FHIR resource server. While CDS Hooks shares the underlying technical framework and standards as SMART on FHIR, the CDS Hooks workflow must accommodate the automated, low-latency delivery of an access token to the CDS service.

With CDS Hooks, if the EHR wants to provide the CDS Service direct access to FHIR resources, the EHR creates an access token prior to invoking the CDS Service, passing this token to the CDS Service as part of the service call. This approach remains compatible with OAuth 2.0's bearer token protocol while minimizing the number of HTTPS round-trips and the service invocation latency. The EHR remains in control of creating an access token that is associated with the specific CDS Service, user, and context of the invocation. As the CDS Service executes on behalf of a user, the data to which the CDS Service is given access MUST BE limited to the same restrictions and authorizations afforded the current user. As such, the access token SHALL BE scoped to:

  • The CDS Service being invoked
  • The current user

Passing the Access Token to the CDS Service

The access token is specified in the CDS Service request via the OPTIONAL fhirAuthorization request parameter. This parameter is an object that contains both the access token as well as other related information. If the EHR chooses not to pass along an access token, the fhirAuthorization parameter is omitted.

Field Optionality Type Description
access_token REQUIRED string This is the OAuth 2 access token that provides access to the FHIR server.
token_type REQUIRED string Fixed value: Bearer.
expires_in REQUIRED integer The lifetime in seconds of the access token.
scope REQUIRED string The scopes the access token grants the CDS Service.
subject REQUIRED string The OAuth 2.0 client identifier of the CDS Service, as registered with the EHR's authorization server.

The scopes granted to the CDS Service via the scope field are defined by the SMART on FHIR specification.

The expires_in value is established by the authorization server and SHOULD BE very short lived, as the access token must be treated as a transient value by the CDS Service.

Below is an example fhirAuthorization parameter:

1
2
3
4
5
6
7
8
9
{
  "fhirAuthorization" : {
    "access_token" : "some-opaque-fhir-access-token",
    "token_type" : "Bearer",
    "expires_in" : 300,
    "scope" : "patient/Patient.read patient/Observation.read",
    "subject" : "cds-service4"
  }
}

CDS Service Response

Card Array

Field Optionality Type Description
cards REQUIRED array An array of Cards. Cards can provide a combination of information (for reading), suggested actions (to be applied if a user selects them), and links (to launch an app if the user selects them). The EHR decides how to display cards, but we recommend displaying suggestions using buttons, and links using underlined text.

If your CDS Service has no decision support for the user, your service should return a 200 HTTP response with an empty array of cards.

Response when no decision support is necessary for the user

1
2
3
{
  "cards": []
}

Card Attributes

Each Card is described by the following attributes.

Field Optionality Type Description
summary REQUIRED string One-sentence, <140-character summary message for display to the user inside of this card.
detail OPTIONAL string Optional detailed information to display; if provided MUST BE represented in (GitHub Flavored) Markdown without HTML. (For non-urgent cards, the EHR MAY hide these details until the user clicks a link like "view more details...".)
indicator REQUIRED string Urgency/importance of what this card conveys. Allowed values, in order of increasing urgency, are: info, warning, hard-stop. The EHR MAY use this field to help make UI display decisions such as sort order or coloring. The value hard-stop indicates that the workflow should not be allowed to proceed.
source REQUIRED object Grouping structure for the Source of the information displayed on this card. The source should be the primary source of guidance for the decision support the card represents.
suggestions OPTIONAL array of Suggestions Allows a service to suggest a set of changes in the context of the current activity (e.g. changing the dose of the medication currently being prescribed, for the medication-prescribe activity). If used, the user MUST BE allowed to choose no more than one suggestion.
links OPTIONAL array of Links Allows a service to suggest a link to an app that the user might want to run for additional information or to help guide a decision.

Source

The Source is described by the following attributes.

Field Optionality Type Description
label REQUIRED string A short, human-readable label to display for the source of the information displayed on this card. If a url is also specified, this may be the text for the hyperlink.
url OPTIONAL URL An optional absolute URL to load (via GET, in a browser context) when a user clicks on this link to learn more about the organization or data set that provided the information on this card. Note that this URL should not be used to supply a context-specific "drill-down" view of the information on this card. For that, use link.url instead.
icon OPTIONAL URL An optional absolute URL to an icon for the source of this card. The icon returned by this URL should be in PNG format, an image size of 100x100 pixels, and must not include any transparent regions.

Suggestion

Each Suggestion is described by the following attributes.

Field Optionality Type Description
label REQUIRED string Human-readable label to display for this suggestion (e.g. the EHR might render this as the text on a button tied to this suggestion).
uuid OPTIONAL string Unique identifier for this suggestion. For details see Suggestion Tracking Analytics
actions OPTIONAL array Array of objects, each defining a suggested action. Within a suggestion, all actions are logically AND'd together, such that a user selecting a suggestion selects all of the actions within it.
Suggestion Tracking Analytics

Whenever a user clicks a displayed label (e.g., button) from a "suggestion" card, the EHR uses the suggestion uuid to notify the CDS Service's analytics endpoint via a POST with an empty body:

1
`POST {baseUrl}/cds-services/{serviceId}/analytics/{uuid}`

If a suggestion has no uuid, the EHR does not send a notification.

Action

Each Action is described by the following attributes.

Field Optionality Type Description
type REQUIRED string The type of action being performed. Allowed values are: create, update, delete.
description REQUIRED string Human-readable description of the suggested action. May be presented to the end-user.
resource OPTIONAL object Depending upon the type attribute, a new resource or the id of a resource. For a type of create, the resource attribute contains a new FHIR resource to apply within the current activity (e.g. for medication-prescribe, this holds the updated prescription as proposed by the suggestion). For delete, this is the id of any resource to remove from the current activity (e.g. for the order-review activity, this would provide a way to remove an order from the pending list). In activities like medication-prescribe where only one "content" resource is ever relevant, this field may be omitted. For update, this holds the updated resource to modify from the current activity (e.g. for the order-review activity, this would provide a way to annotate an order from the pending list with an assessment).

Each Link is described by the following attributes.

Field Optionality Type Description
label REQUIRED string Human-readable label to display for this link (e.g. the EHR might render this as the underlined text of a clickable link).
url REQUIRED URL URL to load (via GET, in a browser context) when a user clicks on this link. Note that this may be a "deep link" with context embedded in path segments, query parameters, or a hash.
type REQUIRED string The type of the given URL. There are two possible values for this field. A type of absolute indicates that the URL is absolute and should be treated as-is. A type of smart indicates that the URL is a SMART app launch URL and the EHR should ensure the SMART app launch URL is populated with the appropriate SMART launch parameters.
appContext OPTIONAL string An optional field that allows the CDS Service to pass context regarding the launch of this SMART app from the CDS card to the SMART app. The appContext field should only be valued if the link type is smart and is not valid for absolute links. The appContext field and value will be sent to the SMART app as part of the OAuth 2 access token response, alongside the other launch context when the SMART app is launched.

Example

Example response

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
{
  "cards": [
    {
      "summary": "Example Card",
      "indicator": "info",
      "detail": "This is an example card.",
      "source": {
        "label": "Static CDS Service Example",
        "url": "https://example.com",
        "icon": "https://example.com/img/icon-100px.png"
      },
      "links": [
        {
          "label": "Google",
          "url": "https://google.com",
          "type": "absolute"
        },
        {
          "label": "Github",
          "url": "https://github.com",
          "type": "absolute"
        },
        {
          "label": "SMART Example App",
          "url": "https://smart.example.com/launch",
          "type": "smart",
          "appContext": "module-123"
        }
      ]
    },
    {
      "summary": "Another card",
      "indicator": "warning",
      "source": {
        "label": "Static CDS Service Example"
      }
    }
  ]
}

Security and Safety

Security and safety risks associated with the CDS Hooks API include:

  1. The risk that confidential information and privileged authorizations transmitted between an EHR and a CDS Service could be surreptitiously intercepted by an attacker;
  2. The risk that an attacker masquerading as a legitimate CDS Service could receive confidential information or privileged authorizations from an EHR, or could provide to an EHR decision support recommendations that could be harmful to a patient;
  3. The risk that an attacker masquerading as a legitimate service-subscribing EHR (i.e., man-in-the-middle) could intercept and possibly alter data exchanged between the two parties.
  4. The risk that a CDS Service could embed dangerous suggestions or links to dangerous apps in Cards returned to an EHR.
  5. The risk that a CDS Hooks browser-based deployment could be victimized by a Cross-Origin Resource Sharing (CORS) attack.
  6. The risk that a CDS Service could return a decision based on outdated patient data, resulting in a safety risk to the patient.

CDS Hooks defines a security model that addresses these risks by assuring that the identities of both the CDS Service and the EHR are authenticated to each other; by protecting confidential information and privileged authorizations shared between an EHR and a CDS Service; by recommending means of assuring data freshness; and by incorporating business mechanisms through which trust is established and maintained between an EHR and a CDS Service.

Trusting CDS Services

Prior to enabling EHRs to request decision support from any CDS Service, the EHR vendor and/or provider organization is expected to perform due diligence on the CDS Service provider. Each EHR vendor/provider is individually responsible for determining the suitability, safety and integrity of the CDS Services it uses, based on the organization's own risk-management strategy. Each EHR vendor/provider SHOULD maintain a "white list" (and/or "black list") of the CDS Services it has vetted, and the Card links that have been deemed safe to display from within the EHR context. Each provider organization is expected to work with its EHR vendor to choose what CDS Services to allow and to negotiate the conditions under which the CDS Services may be called.

Once a CDS Service provider is selected, the EHR vendor/provider negotiates the terms under which service will be provided. This negotiation includes agreement on patient data elements that will be prefetched and provided to the CDS Service, data elements that will be made available through an access token passed by the EHR, and steps the CDS Service must take to protect patient data and access tokens. To enable the EHR authorization server to authorize CDS Service access to FHIR resources, the CDS Service is registered as a client to the EHR authorization server. These business arrangements are documented in the service agreement.

Every interaction between an EHR and a CDS Service is initiated by the EHR sending a service request to a CDS Service endpoint protected using the Transport Layer Security protocol. Through the TLS protocol the identity of the CDS Service is authenticated, and an encrypted transmission channel is established between the EHR and the CDS Service. Both the Discovery endpoint and individual CDS Service endpoints are TLS secured.

The EHR’s authorization server is responsible for enforcing restrictions on the CDS Services that may be called and the scope of the FHIR resources that may be prefetched or retrieved from the FHIR server. Therefore, all CDS Services to be called from within an EHR system MUST BE pre-registered with the authorization server of that EHR. Pre-registration MUST include registering a CDS client identifier, and agreeing upon the scope of FHIR access that is minimally necessary to provide the clinical decision support required.

Trusting EHRs

The service agreement negotiated between the EHR vendor/provider and the CDS Service provider will include obligations the EHR vendor/provider commits to the CDS Service provider. Some agreements may include the use of mutual TLS, in which both ends of the channel are authenticated.

However, mutual TLS is impractical for many organizations, and because the EHR initiates the TLS channel set-up, only the CDS Service endpoint will be authenticated. To enable the CDS Service to authenticate the identity of the EHR, CDS Hooks uses digitally signed JSON web tokens (JWT).

Each time an EHR transmits a request to a CDS Service, the request MUST include an Authorization header presenting the JWT as a “Bearer” token:

1
Authorization:  Bearer {{JWT}}

Note that this is for every single CDS Service call, whether that be a Discovery call, a single CDS Service invocation, or multiple exchanges relating to a single service. Also note that mutual TLS MAY be used alongside JSON web tokens to establish trust of the EHR by the CDS Service.

The EHR MUST use its private key to digitally sign the JWT, using the JSON Web Signatures (rfc7515) standard.

The JWT header contains the following fields (see rfc7515 section 4.1 for further information on these standard headers):

Field Optionality Type Value
alg REQUIRED string The cryptographic algorithm used to sign this JWT.
kid REQUIRED string The identifier of the key-pair used to sign this JWT. This identifier MUST be unique within the EHR's JWK Set.
typ REQUIRED string Fixed value: JWT.
jku OPTIONAL url The URL to the JWK Set containing the public key(s).

The JWT payload contains the following fields:

Field Optionality Type Value
iss REQUIRED string The URI of the issuer of this JWT. Note that the JWT may be self-issued by the EHR, or may be issued by a third-party identity provider.
sub REQUIRED string Client_id of the EHR.
aud REQUIRED string or array of string The CDS Service endpoint that is being called by the EHR. (See more details below).
exp REQUIRED number Expiration time integer for this authentication JWT, expressed in seconds since the "Epoch" (1970-01-01T00:00:00Z UTC).
iat REQUIRED number The time at which this JWT was issued, expressed in seconds since the "Epoch" (1970-01-01T00:00:00Z UTC).
jti REQUIRED string A nonce string value that uniquely identifies this authentication JWT (used to protect against replay attacks)

CDS Services SHOULD whitelist the iss, jku and sub fields to only the EHRs they trust.

Per rfc7519, the aud value is either a string or an array of strings. For CDS Hooks, this value MUST BE the URL of the CDS Service endpoint being invoked. For example, consider a CDS Service available at a base URL of https://cds.example.org. When the EHR invokes the CDS Service discovery endpoint, the aud value is either "https://cds.example.org/cds-services" or ["https://cds.example.org/cds-services"]. Similarly, when the EHR invokes a particular CDS Service (say, some-service), the aud value is either "https://cds.example.org/cds-services/some-service" or ["https://cds.example.org/cds-services/some-service"].

The EHR MUST make its public key, expressed as a JSON Web Key (JWK) in a JWK Set, as defined by rfc7517. The kid value from the JWT header allows a CDS Service to identify the correct JWK in the JWK Set that can be used to verify the signature.

The EHR MAY make its JWK Set available via a URL identified by the jku header field, as defined by rfc7515 4.1.2. If the jku header field is ommitted, the EHR and CDS Service SHALL communicate the JWK Set out-of-band.

An example JSON web token header and payload:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
  "alg": "ES384",
  "typ": "JWT",
  "kid": "example-kid",
  "jku": "https://fhir-ehr.example.com/jwk_uri"
}

{
  "iss": "https://fhir-ehr.example.com/",
  "sub": "client_id",
  "aud": "https://cds.example.org/cds-services/some-service",
  "exp": 1422568860,
  "iat": 1311280970,
  "jti": "ee22b021-e1b7-4611-ba5b-8eec6a33ac1e"
}

Using the above JWT payload, the complete JWT as passed in the Authorization HTTP header would be:

1
Authorization: Bearer eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCIsImtpZCI6ImV4YW1wbGUta2lkIiwiamt1IjoiaHR0cHM6Ly9maGlyLWVoci5leGFtcGxlLmNvbS9qd2tfdXJpIn0.eyJpc3MiOiJodHRwczovL2ZoaXItZWhyLmV4YW1wbGUuY29tLyIsInN1YiI6ImNsaWVudF9pZCIsImF1ZCI6Imh0dHBzOi8vY2RzLmV4YW1wbGUub3JnL2Nkcy1zZXJ2aWNlcy9zb21lLXNlcnZpY2UiLCJleHAiOjE0MjI1Njg4NjAsImlhdCI6MTMxMTI4MDk3MCwianRpIjoiZWUyMmIwMjEtZTFiNy00NjExLWJhNWItOGVlYzZhMzNhYzFlIn0.230VxOubItskK-HCzdfjR5Y76nEydquQoqK-JDHbl8y8wzo-7HJetYpY1R4rytp_yJJCc8DULX9G5llPKx6opQ

Cross-Origin Resource Sharing

Cross-origin resource sharing (CORS) is a W3C standard mechanism that uses additional HTTP headers to enable a web browser to gain permission to access resources from an Internet domain different from that from which the browser is currently accessing. CORS is a client-side security mechanism with well-documented security risks.

CDS Services and browser-based EHRs will require CORS support. A secure implementation guide for CORS is outside of the scope of this CDS Hooks specification. Organizations planning to implement CDS Hooks with CORS support are referred to the Cross-Origin Resource Sharing section of the OWASP HTML5 Security Cheat Sheet.

Extensions

The specification is not prescriptive about support for extensions. However, to support extensions, the specification reserves the name extension and will never define an element with that name, allowing implementations to use it to provide custom behavior and information. The value of an extension element should be a pre-coordinated JSON object.

For example, an extension on a request could look like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
   "hookInstance" : "d1577c69-dfbe-44ad-ba6d-3e05e953b2ea",
   "fhirServer" : "http://fhir.example.org:9080",
   "hook" : "patient-view",
   "user" : "Practitioner/example",
   "extension" : {
      "com.example.timestamp": "2017-11-27T22:13:25Z",
      "myextension-practitionerspecialty" : "gastroenterology"
   }
}

As another example, an extension defined on the discovery response could look like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
  "services": [
    {
      "title": "Example CDS Service Discovery",
      "hook": "patient-view",
      "id": "patientview",
      "prefetch": {
        "patient": "Patient/{{context.patientId}}"
      },
      "description": "clinical decision support for patient view",
      "extension": {
          "example-client-conformance": "http://hooks.example.org/fhir/102/Conformance/patientview"
      }
    }
  ]
}