openEHR logo

SMART on openEHR (SMART)

Issuer: openEHR Specification Program

Release: ITS-REST latest

Status: DEVELOPMENT

Revision: [latest_issue]

Date: [latest_issue_date]

Keywords: JSON, REST, SMART, OAuth2, OIDC, Authentication, Authorization, Application, App

openEHR components
© 2023 - 2024 The openEHR Foundation

The openEHR Foundation is an independent, non-profit foundation, facilitating the sharing of health records by consumers and clinicians via open specifications, clinical models and open platform implementations.

Licence

image Creative Commons Attribution-NoDerivs 3.0 Unported. https://creativecommons.org/licenses/by-nd/3.0/

Support

Issues: Problem Reports
Web: specifications.openEHR.org

Amendment Record

Issue Details Raiser Completed

ITS_REST Release (unreleased)

1.0.0

SPECITS-69. Adding "SMART on openEHR" specifications.

S Ramesh,
S Iancu

09 Sep 2023

Acknowledgements

Primary Author

  • Sidharth Ramesh; Medblocks.

  • Sebastian Iancu; Architect, Code24, Netherlands

Contributors

This specification has benefited from formal and informal input from the openEHR and wider health informatics community. The openEHR Foundation would like to recognise the following for their contributions.

  • Ian McNicoll MD, FreshEHR, UK

  • Bostjan Lah, Senior Architect, Better, Slovenia

A significant part of the design ideas of this specification was derived from:

  • the SMART on FHIR protocol - SMART App Launch Release 2.1.0, published by HL7® FHIR® standard

Trademarks

  • 'openEHR' is a registered trademark of the openEHR Foundation

  • HL7® and FHIR® are the registered trademark of the Health Level Seven International and their use does not constitute endorsement by HL7

  • SMART™ and the SMART logos are trademarks of The Children’s Medical Center Corporation. Used with permission.

1. Preface

1.1. Purpose

This document describes the SMART protocol for an openEHR platform.

The intended audience includes:

  • EHR systems, Platform or Application vendors;

  • Standards bodies producing health informatics standards;

  • Solution vendors.

Prerequisite documents for reading this document include:

1.3. Status

This specification is in the DEVELOPMENT state. The development version of this document can be found at https://specifications.openehr.org/releases/ITS-REST/latest/smart_app_launch.html.

Known omissions or questions are indicated in the text with a 'to be determined' paragraph, as follows:

TBD: (example To Be Determined paragraph)

1.4. Feedback

Feedback may be provided on the openEHR ITS forum.

Issues may be raised on the specifications Problem Report tracker.

To see changes made due to previously reported issues, see the ITS-REST component Change Request tracker.

2. Overview

2.1. Background

SMART stands for “Substitutable Medical Applications and Reusable Technologies”, a healthcare standard through which applications can access clinical information through a data store. It was initially proposed by SMART Health IT project (run by Boston Children’s Hospital Computational Health Informatics Program) and was later specified as SMART on FHIR, a protocol which works on top of the FHIR APIs facilitating access to data. The specification builds on OAuth2 and OpenID Connect (OIDC), which are industry standards for authentication and authorization, and allows 3rd-party applications to authorize and seamlessly work with any system that implements the protocol.

2.2. Glossary

Term Definition

Vendor

An entity that provides software to end-users.

User

This is the real person who is using the Application to perform some function. This is often referred to as the "end-user".

Application

A software application developed by a vendor, designed to work with the Platform and/or Launcher built by the same or different vendor. This is also known as the "client" in terms of OAuth roles, and often referred to as the "SMART App" by SMART on FHIR specification.

Platform

A software system consisting at least of an Authorization Server, an openEHR Clinical Data Repository (CDR) and a FHIR Server, providing openEHR REST APIs, FHIR APIs and potentially other APIs. This is sometimes also known in the SMART on FHIR specification as the "EHR system". The authentication and authorization server that provides APIs consistent with the OAuth2 framework specification and the SMART on openEHR protocol.

Launcher

User-facing software, usually built by the Platform vendor, that serves to launch other Applications within a context of a Patient or Practitioner. The Launcher can be part of the Platform (i.e. a Portal) or a completely separate application.

EHR

A (session) context that relates to an openEHR EHR container and the associated Patient, representing the subject on which the Application will work.

Note

The SMART on FHIR specifications uses the term 'EHR' and 'EHR system' to refer to a software system comprising a FHIR Server, Authorization Server and potentially other components, including a Launcher. On the other hand, openEHR has specification for an EHR Information Model, including a root EHR container.

In order to avoid any confusion between the meaning of 'EHR' in the context of SMART, this specification will only use this term in relation with openEHR concepts (i.e. EHR type, EHR ID, etc.), and will use substitutes for FHIR’s 'EHR' concept.

2.3. Why SMART on openEHR?

A popular vision nowadays is considering that a single software vendor cannot provide all the necessary tools and software for a healthcare system while still maintaining a high level of quality and a low cost of ownership. Independent vendors who focus on a specific topic or problem to be solved may have an edge over monolithic "suites" of software that try to do everything.

In practice, this requires applications from multiple vendors working together to provide a complete solution, often named "best-of-breed" architecture. This is implemented currently by long tedious manual "integration" phase, where the multiple vendors collaborate to make their software work together - a very expensive process, often a major barrier to entry for new vendors.

The SMART specification aims to solve this problem by providing a standard way for systems and applications to work together, as it defines a contract between the Application vendor and the Platform vendor. This contract covers the following requirements:

  • The Application should have the ability to be hosted on a domain owned by the Application vendor

  • The Platform should have the ability to be hosted on a domain owned by the Platform vendor

  • The Application needs a way to discover API services offered by the Platform

  • The Application needs a way to authenticate with the Platform to access the APIs offered by the Platform

  • The Application needs a way to understand the "context" while they are open, by letting the Platform handle EHR and Episode selection

  • The Application needs a way to embed within the Platform's user interface while maintaining the "context" to provide a seamless user experience

The SMART on openEHR specification aims to maintain compatibility with SMART on FHIR while making this protocol work also with openEHR REST APIs and potentially more other APIs. It is meant to describe a framework for the following aspects:

2.4. Requirements

The openEHR Reference Model and openEHR REST API specification provide a foundation for interoperable Applications. For such applications to be truly portable between systems and vendors, there is a requirement for a uniform authentication and authorization process.

Many of such applications also function in the context of a single EHR or Patient, and potentially of a single Episode. Selection of this context also becomes essential before lunching the Application.

3. Application Registration

An Application needs to first register itself with the Platform that it needs to integrate with. This process involves the followings:

  • The Application registers with the Platform by providing the appropriate ID, OAuth2 Scopes, Launch Contexts, Domains, Redirect URLs (redirect_uri) etc.

  • The Application obtains credentials like the client_id, JSON Web Keys or client_secret from the Platform for authentication and authorization.

While this process could be formalised and automated in the future using protocols like OAuth2 Dynamic Client Registration Protocol, the current recommendation is to do this out-of-band in a way that makes sense for the Application Vendor and the Platform Vendor. For example, the Platform vendor could offer a Registration Page that Application Vendors could use to register their applications, and can have an approval and audit mechanism before applications are registered.

4. Service Discovery

A Platform usually has multiple endpoints of interest. Some of these are the OAuth2’s endpoints, like the Token and Authentication endpoints, while others are data resource or service endpoints defined by the openEHR REST APIs, FHIR APIs, DICOMWeb APIs, or other vendor’s proprietary APIs.

The SMART Service Discovery builds on the FHIR .well-known/smart-configuration and enables a Platform to advertise multiple services alongside the OAuth2 endpoints for authentication and any available SMART capabilities.

smart service discovery
Figure 1. SMART Service Discovery

Given a Platform base URL of https://platform.example.com, the SMART configuration endpoint should be available at the location formed by appending /.well-known/smart-configuration to their base URL, i.e. at https://platform.example.com/.well-known/smart-configuration. This base URL may also contain a path component, e.g. https://platform.example.com/gateway/v1/.

Note

In order to maintain compatibility with SMART on FHIR applications, it is recommended that the platform vendor makes the Platform base URL (e.g. https://platform.example.com) also the FHIR server base URL, fulfilling FHIR SMART apps expectations, which assumes that the iss launch parameter is the same as the issuer endpoint advertised in the .well-known/smart-configuration and represents the FHIR server endpoint.

Responses for /.well-known/smart-configuration requests should be always returned in JSON format, using the application/json mime type. An example will look like this:

{
  "issuer": "https://platform.example.com",
  "jwks_uri": "https://platform.example.com/.well-known/jwks.json",
  "authorization_endpoint": "https://platform.example.com/auth/authorize",
  "token_endpoint": "https://platform.example.com/auth/token",
  "services": {
    "org.openehr.rest" : {
      "baseUrl":"https://platform.example.com/openehr/rest/v1",
      "description": "The openEHR REST APIs baseUrl",
      "documentation": "https://example.com/openehr/docs",
      "openapi": "https://example.com/openehr/rest/v1/openapi.json"
    },
    "org.fhir.rest" : {
      "baseUrl":"https://platform.example.com/",
      "description": "The FHIR APIs baseUrl"
    },
    "com.amazon.aws.s3.rest": {
      "baseUrl":"https://s3.example.com/storage",
      "documentation": "https://example.com/s3/docs",
      "openapi": "https://example.com/s3/openapi.json"
    },
    "com.example.demographics": {
      "baseUrl":"https://demographics.example.com/rest"
    }
  },
  "token_endpoint_auth_methods_supported": [
    "client_secret_basic",
    "private_key_jwt"
  ],
  "grant_types_supported": [
    "authorization_code",
    "client_credentials"
  ],
  "registration_endpoint": "https://platform.example.com/auth/register",
  "scopes_supported": ["openid", "profile", "launch", "launch/patient", "patient/*.rs", "user/*.rs", "offline_access"],
  "response_types_supported": ["code"],
  "management_endpoint": "https://platform.example.com/user/manage",
  "introspection_endpoint": "https://platform.example.com/user/introspect",
  "revocation_endpoint": "https://platform.example.com/user/revoke",
  "code_challenge_methods_supported": ["S256"],
  "capabilities": [
    "launch-ehr",
    "permission-patient",
    "permission-v2",
    "client-public",
    "client-confidential-symmetric",
    "context-ehr-patient",
    "sso-openid-connect",
    "context-openehr-ehr",
    "openehr-permission-v1",
	"launch-base64-json"
  ]
}

The details of the /.well-known/smart-configuration are described in the sections below.

4.1. Authentication endpoints

The following configurations keys should be exactly the same as in the OAuth2 + OIDC protocol’s .well-known/openid-configuration as per OpenID Connect Discovery 1.0 and FHIR specifications:

  • isuer

  • jwks_uri

  • authorization_endpoint

  • token_endpoint

  • token_endpoint_auth_methods_supported

  • grant_types_supported

  • scopes_supported

  • response_types_supported

  • introspection_endpoint

  • revocation_endpoint

  • code_challenge_methods_supported

4.2. Services

A response from the SMART Configuration endpoint should include besides the FHIR metadata also a hash of all available services on the Platform. The services section allows the application to discover the APIs of all services that can be used along with their description and documentation. The services section is represented as a hash, where the key is represented by a reverse domain name of the service (e.g. org.openehr.rest), and the value represents the service specification.

Listed services should include minimally the openEHR REST APIs endpoints specification available on the Platform, using the key org.openehr.rest. For consistency reason, it is recommended to also include the specification of the FHIR server using the key org.fhir.rest:

  • org.openehr.rest: The base URL of the openEHR REST APIs (required)

  • org.fhir.rest: The base URL of the FHIR APIs (recommended)

The Platform vendor may add additional services to the services list, for example:

  • org.dicomstandard.dicomweb.rest: The base URL of the DICOMWeb REST API

  • com.amazon.aws.s3.rest: The base URL of an AWS S3 compatible REST API

  • com.example.demographics: The base URL of a proprietary service that is not part of the openEHR, FHIR or DICOMWeb specifications

Each service specification should include the following configurations:

  • baseUrl: The base URL of the service (required)

  • description: A short description of the service

  • documentation: A URL to the documentation of the service

  • openapi: A URL to the OpenAPI specification of the service

As an example, the openEHR REST APIs endpoints may be described as:

{
    "org.openehr.rest" : {
        "baseUrl":"https://platform.example.com/openehr/rest/v1",
        "description": "The openEHR REST API baseUrl",
        "documentation": "https://platform.example.com/openehr/docs",
        "openapi": "https://platform.example.com/openehr/rest/v1/openapi.json"
    }
}

4.3. Capabilities

The capabilities section is an array that should include all relevant SMART capabilities. Besides FHIR capabilities, the following additional values should be used in order to indicate the ability to launch an application using openEHR artefacts:

  • context-openehr-ehr - support for EHR-level launch context (requested by launch/patient scope, conveyed via ehrId token parameter).

  • context-openehr-episode - support for Episode-level launch context (requested by launch/episode scope, conveyed via episodeId token parameter). This capability is deemed experimental.

  • openehr-permission-v1 - support for the scope and authorization scheme for openEHR REST APIs as described below

  • launch-base64-json - support for the launch URL parameter being a base64 encoded JSON of the context.

5. Authentication, Authorization and Scopes

In general authentication is the process of verifying who the end-user is, while the authorization is the process of verifying what specific functionality or data an end-user has access to. The SMART profile on the underlying OAuth2.0 framework specifications is designed primarily as a mean of requesting and granting access to resources, focusing mainly on the aspects of the authorization process.

The following sections describes these processes in relation with the SMART on openEHR protocol.

5.1. Authentication

In accordance with SMART protocol, the authentication is often a step of the authorization process. Also, for the end-user identity verification steps of the authentication protocol an external framework should be used, such as OpenID Connect (OIDC), but the exact method is beyond the scope of this specification.

5.1.1. Available flows

The client Application can authenticate with the Platform using the SMART on openEHR, based on the following flows:

The supported authentication flows should be advertised by the Platform in the .well-known/smart-configuration endpoint.

SMART protocol distinguish two types of authentication types:

The following flows are considered legacy and should not be used:

5.1.2. Application types

The recommended authentication flow depends also on the type of the client Application. There is a distinction between applications based on whether they can hold their credentials (e.g. client secrets) or are capable to secure the client authentication using other means. The following types of client applications are considered by SMART:

  • Confidential applications: they have the ability to hold a credentials. This includes web applications running on a trusted server, uses additional technology for higher security and backend applications.

  • Public applications: they do not have the ability to hold a client secret. This includes mobile applications and single page web applications.

The distinction on the client application types can also be made on the basis of the user interaction. The following types are considered:

  • Patient facing: The patient is the direct end-user of this application, or is opened up by a practitioner within the context of a single patient. It can also be opened within the context of an episode related to a patient, but is optional.

  • Practitioner facing: The practitioner is the end-user of this application. It can be optionally opened up within the context of a patient, or episode.

  • Backend service: The application is not directly used by an end-user, but is used by another applications or services in the background.

It is recommended that Patient and Practitioner facing applications use one of the Authorization Code Flows to obtain necessary user information and context. Confidential clients can use the Authorization Code Flow with PKCE or the Authorization Code Flow with Client Secret. Public clients should always use the Authorization Code Flow with PKCE. Backend applications should always use confidential clients and use the JWT Assertion Flow with JWS or the Client Credentials Flow.

The following table shows the recommended flow for a few example applications:

Application Example Client Type User interaction type Recommended Flow

Single Page Web Application for a Patient Portal

Public

Patient facing

Authorization Code Flow with PKCE

Mobile Application for tracking heart rate

Public

Patient facing

Authorization Code Flow with PKCE

Web Application with Backend for cardiology management

Confidential

Practitioner facing

Authorization Code Flow with PKCE or Authorization Code Flow with client_secret

Realtime alert system for hospital

Confidential

Backend service

JWT Assertion Flow with JWS or Client Credentials Flow

5.2. SMART Authorization Flow

Both Patient and Practitioner facing applications have special requirements that cannot be fulfilled only by the standard OAuth2 framework specification. SMART on FHIR specifies that depending on the session context, applications can be launched in two ways:

  1. Standalone launch: The Application is opened directly by the end-user, launched outside the end-user session context on the Platform - e.g. by launching the app at https://myapp.example.com. The application decides which Platform to use based on the user’s selection.

  2. EHR launch: The Application is often embedded within the Platform’s main user-interface (i.e. a Portal) using an iFrame. Additional parameters launch and iss are passed to the Application to indicate the Platform to use, and the launch context - e.g. https://myapp.example.com?launch=123&iss=https://platform.example.com. This launch method is also referred to as Embedded iFrame Launch to avoid potential confusion in relation with openEHR Reference Model EHR specification.

The Authorization Code Flow as defined in OAuth2 framework is a two-step process where:

  1. The client first requests an authorization code from the authorization server by redirecting the user to the authorization_endpoint.

  2. Subsequently, the client exchanges the authorization code for an access token by using the token_endpoint.

The SMART protocol specifies a few modifications to the Authorization Code Flow to enhance it for the use-case of Standalone and Embedded iFrame launch, which are described in the following sections.

5.2.1. Context Selection

In the Standalone launch, a client Application can request (invoke) the Platform for the context selection, if relevant context-\* prefixed capabilities are available on the Platform. Most Patient and Practitioner facing application will also require during authorization process the Platform to determine and send additional context data. This may contain information like the openEHR EHR ID or Patient ID, potentially the Episode ID, and it may be valid for a lifetime of the end-user session.

smart standalone launch
Figure 2. Standalone Launch

This context data can be used to pre-populate the client Application with the correct data. The Platform can do this by automatically inferring the context based on the logged-in user, or can provide a screen right after the consent page to select the context in case of ambiguity.

The Application can request the Platform for openEHR related context selection by passing the following special scopes in the authorization request:

Scope Meaning

launch/patient

Need patient context at launch time (FHIR Patient resource and openEHR EHR). When launching outside the EHR, ask for the openEHR EHR instance to be selected.

launch/episode

Need episode context at launch time (this is experimental, the semantic and the resource is to be determined).

The context data populated by the Platform is returned in the token response along with the id_token and access_token. The following additional parameters (besides those described by FHIR) are added to the token response:

Parameter Meaning

ehrId

The ID of the openEHR EHR instance associated with the FHIR Patient resource selected in the launch.

episodeId

The ID of the Episode selected in the launch (this is experimental, the semantic and the resource is to be determined).

The application can make use of these parameters to render the correct information to the end-user.

Note

The launch scopes and token attributes from SMART on FHIR can also be combined here for backward compatibility, but they are not covered by this specification.

5.2.2. Embedded iFrame Launch

Most Practitioner facing, as well as some Patient facing applications will have to be embedded within the end-user’s web based front-end (i.e. a Portal) by using an iFrame.

The Platform can automatically communicate the correct context for the client Application by passing the launch parameter to the application’s url. The Platform should also provide the iss parameter to indicate its endpoint for the application to use (which for FHIR SMART apps compatibility reasons represents also the FHIR server endpoint). As an example, an application can be launched by a URL like: https://myapp.example.com?launch=123&iss=https://platform.example.com.

smart embedded iframe launch
Figure 3. Embedded iFrame Launch

The application can then use the iss parameter to obtain the Platform configuration from the .well-known/smart-configuration endpoint. It then uses the authorization_endpoint to start the Authorization Code Flow. The launch parameter is passed along to the authorization request.

The following scope is also mandatory while passing the launch parameter:

Scope Meaning

launch

Permission to obtain launch context when Application is launched from an EHR (Embedded iFrame Launch). This should be accompanied by an additional launch parameter in the authorization request.

It is recommended that the launch token be a base64 encoded JSON object, containing the context attributes like the ehrId, along with other attributes. The client Application can use this information to pre-populate itself without initiating an authorization request if it is already authenticated. This will enable a seamless experience for the user when switching between patients while using the application within an iFrame. This capability can be advertised by adding the launch-base64-json capability in the /.well-known/smart-configuration response.

5.3. Scopes for openEHR REST API

The Application can request access to the Platform resources using the OAuth2.0 scopes. SMART defines the scope syntax as follows:

<compartment>/<resource>.<permission>

The scopes are based on 3 different compartments:

  • patient/*: These scopes are used when the EHR ID is present in the context. Only access to resources in the compartment of the EHR ID is allowed.

  • user/*: These scopes are used when the user is identified by the Platform. It is usually a practitioner or an administrator. Only access to resources that the user would usually have access to is allowed.

  • system/*: These scopes are used when the user is not available and the application is a backend confidential application. These scopes are obtained in advance while registering the application and provides (unrestricted) access to resources in the Platform.

For the openEHR REST APIs the following resource expressions are supported:

  • template-<templateId>: Templates which match the <templateId> expression.

  • composition-<templateId>: Compositions of the templates which match the <templateId> expression.

  • aql-<queryName>: AQL Queries that match the <queryName> expression. If the <queryName> is *, then all queries as well as ad-hoc queries are allowed.

The <templateId> in the above definition follows the blob pattern matching delimited by a . period. For example:

  • MyHospital.Template.v0 - Matches only MyHospital.Template.v0

  • *.Template.v0 - Matches MyHospital.Template.v0 and OtherHospital.Template.v0

  • MyHospital.** - Matches MyHospital.Template.v0, MyHospital.Template.v2 and MyHospital.OtherTemplate.v0

  • * - Matches all templates in the system

The <queryName> in the above definition follows the blob pattern matching delimited by . a period. For example:

  • org.openehr::compositions - Matches only org.openehr::compositions

  • org.openehr::* - Matches org.openehr::compositions and org.openehr::bloodpressure

  • org.openehr::** - Matches org.openehr::compositions, org.openehr::bloodpressure, org.openehr::bloodpressure.v1

  • * - Matches all queries and ad-hoc queries

The following permission expressions are supported:

  • c: The ability to create a resource.

  • r: The ability to read a resource.

  • u: The ability to update a resource.

  • d: The ability to delete a resource.

  • s: The ability to search a resource. In case of aql-<queryName> scope, this means the ability to execute the query.

The following table is a maximal representation of the scopes made possible in different compartment, resource and permission combinations:

Scope Meaning

patient/composition-<templateId>.crud

Permission to create, read, update and delete compositions of <templateId> that are within the EHR of the patient in context.

user/composition-<templateId>.crud

Permission to create, read, update and delete compositions of <templateId> that are within the EHRs the logged-in user has access to.

system/composition-<templateId>.crud

Permission to create, read, update and delete compositions of <templateId> of all EHRs in the system.

patient/template-<templateId>.r

Permission to read a template with <templateId>

user/template-<templateId>.crud

Permission to create and read a template with <templateId>

system/template-<templateId>.crud

Permission to create, read, update and delete a template with <templateId>

patient/aql-<queryName>.rs

Permission to read and execute AQL with <queryName> on EHR ID of the patient in context.

user/aql-<queryName>.cruds

Permission to create, read, update, delete and execute AQL with <queryName> on EHR IDs that the logged-in user has access to. If <queryName> is equal to the wildcard *, this scope will allow the ad-hoc query endpoint.

system/aql-<queryName>.cruds

Permission to create, read, update, delete and execute AQL with <queryName>. If <queryName> is equal to the wildcard *, this scope will allow the ad-hoc query endpoint.

References