Skip to content

Latest commit

 

History

History
199 lines (156 loc) · 25.9 KB

KT2_IMPLEMENTATION_GUIDE.md

File metadata and controls

199 lines (156 loc) · 25.9 KB

The Koppeltaal 2.0 implementation Guide

[begrippenlijst]

Introduction

The Koppeltaal 2.0 implementation guide provides a guide for engineers, architects and product owners. This guide attempts to explain in what to expect when implementing Koppeltaal 2.0 in a high over fashion.

Scope and domain

Depending on your application architecture, you must be aware that Koppeltaal 2.0 is deployed in the context of a domain. In case of a multi-tenant solution, you must be aware of the fact that most of the things you need will be domain specific and the architecture you choose must cater for this. If you are starting your application architecture from scratch you might want to consider a deployment-per-domain strategy and simplify your application architecture. However, such e per-domain deployment strategy might hinder the replication of content between installations.

Changes from 1.x

The aim of Koppeltaal 2.0 is to simplify things and align to standards. The largest change is to switch from a message bus architecture to a single truth FHIR resource service where information is exchanged. The push aspect of the message bus architecture is replaced by a subscription model. The major FHIR change is the switch from FHIR DSTU3 to FHIR R4.

Standards, standards, and standards

The Koppeltaal 2.0 standard in is core is composed of many other open standards, shown in the table below.

Standard Use
HTI Launch of modules
FHIR R4 Exchange of information
FHIR R4 Rest API API interaction with FHIR resources
SMART on FHIR app launch Launch of modules
SMART on FHIR backend services Identification of client applications
OAuth 2.0 Client Credentials Grant Identification of client applications

The parts that are custom defined for Koppeltaal 2.0 are:

  • The security model and authorization rules
  • The combination of HTI and SMART on FHIR app launch

Security and permission model

Trust model

Koppeltaal uses a application level trust model, so applications get a role with a set of permissions that give access to FHIR resources. In Koppeltaal 2.0, the individual user of the system are NOT identified, it is the responsibility of the application to enforce user level restrictions. Applications are assigned roles, Koppeltaal 2.0 uses a form of Role-Based Access Control (RBAC). The trust model is based on a central authority in the Koppeltaal 2.0 domain, the authorization service, to which all access related tasks are delegated to. The authorization service hands out access to the API, validates launches and provides token introspection.

Key pairs and secrecy

In order to participate in a domain, an application needs to generate a keypair and publish the public part by JWKS. The secret leg of the keypair must be kept secret. If the private part is leaked, others can easily take over your application role in the domain. By making use of JWKS it is make possible to have multiple key pairs active and change key pairs with minimal effort. It is advised to not store and share the private keys, instead to keep the private part in memory and disseminate the public part by JWKS.

Public key sharing

The public keys should be published by providing a JWKS URL to the Koppeltaal 2.0 domain. This URL contains a list of public keys identified by Key ID's (kid). These Key ID's must match the kid header of the JWTs that are generated by the application to identify itself. This JWKS URL is a way of publishing the verifications methods of the application. The URL must be public accessible. It is discouraged to use a common or well-known URL path for this URL.

Standards and specifications involved:

Roles & permissions

Applications in a domain get assigned a role by the domain administrator. This role is built up out of permissions to resources. These permissions are expressed in .. format.

  1. Resource: linked to a FHIR resource type.
  2. Action: a set if Create (C), Read (R), Update (U) of Delete (D) actions.
  3. Scope: one of the following:
    • OWN: access your own resources.
    • GRANTED: a list of applications
    • ALL: all resources. The "ownership" of a resource is defined by the resource-origin extension field. This field refers to the Device of the owning application.

Delegated trust

The authorization service plays a central role in the trust infrastructure of Koppeltaal 2.0. The authorization service provided access_tokens to the FHIR Rest API, validates the launch with SMART on FHIR app launch and token introspection.

Standards and specifications involved:

Koppeltaal 2.0 Data model

The Koppeltaal 2.0 profile is published in the Koppeltaal 2.0 Simplifier profile.

Resource Type Profile Usage
Organization KT_Organization A healthcare institution, location or department.
Device KT_Device An Application Instance. This resource is created by the Administration Portal when a connection request for an Application in the Domain is approved. At that time, the ClientId is also assigned. This resource cannot be modified by applications.
ActivityDefinition KT_ActivityDefinition Describes an eHealth Module that can be assigned to a patient.
Patient KT_Patient Represents the patient.
CareTeam KT_CareTeam Represents a Care Team. That can be patient specific
Practitioner KT_Practitioner Represents the practitioner.
Task KT_Task A Task is created each time a ActivityDefinition is assigned to a Patient. The task has a status that tracks the lifecycle of the task.
Endpoint KT_Endpoint An endpoint describes the URL for the ActivityDefinition by the KT2EndpointExtension.
Subscription KT_Subscription A subscription to notifications about changes to a particular resource type.
AuditEvent KT_AuditEvent Is created for every relevant event in a Connecting Language Domain, such as the creation or modification of a resource instance, the opening or being opened of an eHealth Module via a launch.

Accessing the API

The Koppeltaal 2.0 Rest API can be accessed with an access_token. This token must be acquired by executing the SMART on FHIR backend services flow. This flow consists of a token request that validates the applications's identity and enforces the configured role for the application. The access_token consists of a JWT that contains the information the FHIR Rest API needs to apply the access rules that are in effect for the application.

Standards and specifications involved:

Getting access: generating a JWT to identify yourself

The SMART on FHIR backend services flow is in the core a OAuth2 client credential flow, that makes use of JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants as client credential method. This means that the application needs to:

  1. Generate a key pair that is used for signing the JWT.
  2. Publish the public key in an URL known to the Koppeltaal 2.0 domain.
  3. Sign a JWT as client credential with a kid header matching at least one key in the JWKS file published at 2).
  4. The client credential is provided as part of the token request, the field client_assertion_type is set to urn:ietf:params:oauth:client-assertion-type:jwt-bearer and the JWT is provided as `client_assertion.

Standards and specifications involved:

CRUD operations & versioning

Koppeltaal makes use if the FHIR R4 Rest API as much as possible, with exception to the following:

  • The update method requires a If-Match header.
  • Conditional creates, conditional updates and conditional deletes MAY be supported by the FHIR resource service.
  • Patching and conditional patching is not supported.
  • Deletes are discouraged, lifecycle should be managed through status.
  • Searching does not support the _include, _revinclude, _contained and _containedType parameters.

Standards and specifications involved: FHIR R4 Rest API

Lifecycle entities

The lifecycle of entities are managed by either the active field or the status field of the entity.

Resource Type Profile Usage
Organization active true, The organization's record is in active use.
false, The organization's record is not in active use.
Device status active, the device is available for use.
inactive, The device is no longer available for use.
entered-in-error,The device was entered in error and voided.
unknown, The status of the device has not been determined.
Patient active true, The patients record is in active use.
false, The patients record is not in active use.
CareTeam status active, The care team is currently participating in the coordination and delivery of care
inactive, The care team was, but is no longer, participating in the coordination and delivery of care.
proposed, The care team has been drafted and proposed, but not yet participating in the coordination and delivery of patient care.
suspended, The care team is temporarily on hold or suspended and not participating in the coordination and delivery of care.
entered-in-error, The care team should have never existed.
Practitioner active true, The practitioner's record is in active use.
false, The practitioner's record is not in active use.
Task status draft, The task is not yet ready to be acted upon.
entered-in-error, The task should never have existed and is retained only because of the possibility it may have used.
ready, The task is ready to be performed, but no action has yet been taken. Used in place of requested/received/accepted/rejected when request assignment and acceptance is a given.
in-progress, The task has been started but is not yet complete.
cancelled, The task was not completed.
on-hold, The task has been started but work has been paused.
failed, The task was attempted but could not be completed due to some error.
completed, The task has been completed.
Endpoint status active, This endpoint is expected to be active and can be used.
suspended, This endpoint is temporarily unavailable.
error, This endpoint has exceeded connectivity thresholds and is considered in an error state and should no longer be attempted to connect to until corrective action is taken.
off, This endpoint is no longer to be used.
entered-in-error, This instance should not have been part of this patient's medical record.
test, This endpoint is not intended for production usage.
Subscription status requested, The client has requested the subscription, and the server has not yet set it up.
active, The subscription is active.
error, The server has an error executing the notification.
off, Too many errors have occurred or the subscription has expired.
ActivityDefinition status draft, This resource is still under development and is not yet considered to be ready for normal use.
active, This resource is ready for normal use.
retired, This resource has been withdrawn or superseded and should no longer be used.
unknown, The authoring system does not know which of the status values currently applies for this resource. Note: This concept is not to be used for "other" - one of the listed statuses is presumed to apply, it's just not known which one.
``,

Deletion

The Koppeltaal 2.0 specification discourages the use of deletions in favor of the lifecycle (status and active fields). However, use cases around the right to be forgotten might require the deletion of resources. Therefore the Koppeltaal 2.0 specification does cater for deletions. Some FHIR resources services MAY implement the &expunge operator.

Handling errors and logging

The AuditEvent entity tracks the audit events in Koppeltaal 2.0 that need to be tracked. Fortunately, most of the events are being managed by the FHIR resource service and security service. As an application developer, most of the burden of creating is thereby taken of your hands. However, in a couple of cases an AuditEvent needs to be created. These are:

  • When initiating a launch
  • When receiving a launch
  • When fetching an entity from the FHIR resource service that cannot be processed by your application.

Tracing

The FHIR Rest API makes use of tracing headers in order to be able to link API calls to each other and be able to link API calls to AuditEvents. The fields used to trace the requests are:

Header If missing Description
X-Request-ID Generated Each request needs a unique identifier, generated if missing.
X-Correlation_ID ignored The X-Request-ID of the parent request, if any.
X-Trace-id ignored or generated If provided, this field is passed on to child requests without modification.

In practice, if an application initiates a request to the FHIR Rest API, no headers need to be provided, although it would be neat if the application would set the X-Request-ID header with an UUIDv4 value. The FHIR resource service will generate a X-Request-ID header for the request if it not set anyway, and may generate a X-Trace-id header. If that request initiates a Subscription update request, the update request will be executed with a new X-Request-ID and the X-Correlation_ID filled with the (generated) X-Request-ID and optionally the X-Trace-id of the original request that caused the subscription update. The receiving application now needs te be aware of the headers as it will initiate a read request to the FHIR resource service to fetch the updated resources. The request will require a new X-Request-ID and the X-Correlation_ID needs to be the X-Request-ID from the subscription update request. If present, the X-Trace-id needs to be copied 'as is'.

Get notified on changes

Subscriptions

Logging and tracing headers

Launching

Executing a launch

Receiving a launch

Logging and tracing

The implementation checklist

  1. Generate and securely retain public/private keypairs
  2. Be able publish the public keys in a JWKS endpoint
  3. Develop the logic to generate a JWT to identify your application to the auth service.
  4. Request an access_token to access the API.
  5. Be able to work with FHIR entities
  6. Understand the lifecycle of FHIR entities
  7. Subscriptions & notifications
  8. Synchronization and errors
  9. Staring a launch: generating a JWT
  10. Receiving a launch: execute the SMART on FHIR sequence.