HL7AU - FHIR WG : FHIR SMART App Launch Walkthrough

This walkthrough demonstrates the Australian profile applied to the HL7 International FHIR SMART App Launch STU2 process.

The page is not intended to define the profile any further, just create a narrated walkthrough of the functionality, and the term PMS is used in place of EHR, but they are the same thing.

In this walkthrough we have a PMS (that has a FHIR API and is the FHIR SMART App Host) opens an AU SMART App, and the app at the end makes some requests for data from the PMS' FHIR API.

  1. The PMS Launches the AU SMART App
  2. AU SMART App - Launch Page
  3. PMS Authorization Page
  4. AU SMART App - redirected from PMS & Retrieve PMS Access Token
  5. AU SMART App - retrieves some data from the PMS' FHIR API

As many systems in Australia run on-site, access from the SMART Application to the FHIR server is expected to only be occurring within the browser context running on the Practitioner's desktop environment, and not from some back-end server in the cloud direct into the FHIR server. This then simplifies the network security issues of this type of access, and in some cases doesn't even require an actual web endpoint available, as demonstrated in the Open Source project on github built by Kenneth Myra, and then updated to FHIR R4, SMART v2 and localized according to this specification by Brian Postlethwaite (and a NuGet package made available for Windows legacy desktops - currently in beta).


SystemValueNotes
PMS FHIR Serverhttps://ehr.example.comThe SMART App doesn't need to know this ahead of time, and may be different for every invocation, and may not even be publicly accessible, but must be accessible from the PMS' users browser.
AU SMART App Launch URLhttps://smartapp.com.au/au-smart-launch.htmlThe PMS registers the SMART app, and configures it as accessible to various users, and may have different rights between smart apps and users. This registration will also include that it must be from the patient context.
AU SMART App Redirect URLhttps://smartapp.com.au/au-smart-index.htmlThis is often registered in the PMS to reduce the risk of someone hijacking the SMART App and redirecting to another location.
Client IDsmart-app-client-id

The Client ID is a value that is agreed and configured in the 2 systems.

(There are suggestions that the Auth Server should be the allocator, but will want to ensure that this is managable for all uses, including the hosts, and clients - refer to the implementer question on the main profile page)


1 The PMS Launches the AU SMART App

The PMS user has a patient open, and open's the AU SMART App, resulting in the PMS opening a browser (could be an application embedded browser in a rich client, or an iframe) and navigates to the launch page for the NCSR SMART App.

Navigate: https://smartapp.com.au/au-smart-launch.html?iss=https%3A%2F%2Fehr%2Fexample%2Fcom&launch=xyz123

Noting the iss parameter points to the address of the PMS' FHIR server base address.

2 AU SMART App - Launch Page

The AU SMART App retrieves the PMS' smart configuration

GET: https://ehr.example.com/.well-known/smart-configuration

Response from the PMS FHIR Server:

HTTP Status 200, content-type: application/json

{
  "issuer": "https://ehr.example.com",
  "authorization_endpoint": "https://ehr.example.com/auth/authorize",
  "token_endpoint": "https://ehr.example.com/auth/token",
  "token_endpoint_auth_methods_supported": ["authorize-post"],
  "scopes_supported": ["openid", "profile", "launch", "launch/patient", "launch/location", "patient/*.rs", "user/*.rs", "online_access", "offline_access"],
  "response_types_supported": ["code"],
  "code_challenge_methods_supported": ["S256"],
  "capabilities": [
    "launch-ehr",
    "permission-v2",
    "client-public",
    "client-confidential-symmetric",
    "context-ehr-patient",
    "permission-offline", // for refresh tokens - requested through offline_access scope
    "permission-user", // support for user level scopes e.g. user/Appointment.rs
    "permission-patient", // support for patient level scopes e.g. patient/Observation.rs
    "permission-v2" // support for SMARTv2 granular scope syntax (recommending over v1 scopes)
  ]
}

This provides the AU SMART App the data to know if the server has the capabilities it requires, and specifically, the URLs for the authorization and token endpoints as these are required in the next steps, navigating to the PMS Authorization page, and then when control comes back, to retrieve the access and identity tokens.

Alternately, support for the old security metadata approach through the fhir server's metadata endpoint, in the above case https://ehr.example.com/metadata could be done.

<CapabilityStatement xmlns="http://hl7.org/fhir">
...
<security >
    <extension url="http://fhir-registry.smarthealthit.org/StructureDefinition/oauth-uris" >
        <extension url="authorize" >
            <valueUri value="https://ehr.example.com/auth/connect/authorize"/>
        </extension>
        <extension url="token" >
            <valueUri value="https://ehr.example.com/auth/connect/token"/>
        </extension>
    </extension>
    <cors value="true"/>
    <service >
        <coding >
            <system value="http://hl7.org/fhir/restful-security-service"/>
            <code value="SMART-on-FHIR"/>
        </coding>
        <text value="OAuth2 using SMART-on-FHIR profile (see http://docs.smarthealthit.org/)"/>
    </service>
    <description value="see http://docs.smarthealthit.org/"/>
</security>
...

The AU SMART App will then navigate to the Authorization endpoint retrieved above and send it the required parameters, specifically the launch parameter must be the same value that the PMS sent in the initial launch call.

Navigate: https://ehr.example.com/auth/connect/authorize?
                response_type=code
                &client_id=smart-app-client-id
                &redirect_uri=https%3A%2F%2Fsmartapp.com.au%2Fau-smart-index.html
                &launch=xyz123
                &scope=openid+profile+launch+user%2FPractitioner.rs+user%2FPractitionerRole.rs+user%2FOrganization.rs+patient%2FPatient.rs
                &state=98wrghuwuogerg97
                &aud=https%3A%2F%2Fehr%2Ffhir

3 PMS Authorization Page

The PMS Authorization page must validate that the parameters are correct for the SMART App (correct client id and known redirect_uri), and that these scopes are authorized, and that the user/organization permits this application to have access to this data. This may not require any user interaction if there are no decisions to be made, and can just redirect back to the SMART app.

Navigate: https://smartapp.com.au/au-smart-index.html?code=123abc&state=98wrghuwuogerg97

Noting that the state value here corresponds to the value passed in by the AU SMART App, and the code is the Authorization code that the SMART app must use to retrieve the access/identity token(s).

4 AU SMART App - redirected from PMS & Retrieve PMS Access Token

After obtaining an authorization code, the app trades the code for an access token via HTTP POST to the PMS authorization server’s token endpoint URL, using content-type application/x-www-form-urlencoded, as described in section 4.1.3 of RFC6749).

POST: https://ehr.example.com/auth/token
content-type: application/x-www-form-urlencoded
body:
grant_type=authorization_code
&code=123abc
&redirect_uri=https%3A%2F%2Fsmartapp.com.au%2Fau-smart-index.html
&client_id=smart-app-client-id

This will return the following json result:

{
  "access_token": "m7rt6i7s9nuxkjvi8vsx",
  "token_type": "bearer",
  "expires_in": 3600,
  "scope": "scope=openid profile launch user/Practitioner.rs user/PractitionerRole.rs user/Organization.rs patient/Patient.rs",
  "patient": "1655118",
  "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsIng1YyI6WyJNSUlHWkRDQ0JVeWdBd0lCQWdJQ0loZ3dEUVlKS29aSWh2Y05BUUVMQlFBd2VqRUxNQWtHQTFVRUJoTUNRVlV4RERBS0JnTlZCQW9UQTBkUFZqRVdNQlFHQTFVRUN4TU5TSFZ0WVc1elpYSjJhV05sY3pGRk1FTUdBMVVFQXhNOFZHVnpkQ0JOWldScFkyRnlaU0JCZFhOMGNtRnNhV0VnVDNKbllXNXBjMkYwYVc5dUlFTmxjblJwWm1sallYUnBiMjRnUVhWMGFHOXlhWFI1TUI0WERUSXdNREl4TnpBeU5Ea3hPVm9YRFRJeU1ESXhOekF5TkRreE9Wb3dnZUV4RWpBUUJnb0praWFKay9Jc1pBRVpGZ0poZFRFVE1CRUdDZ21TSm9tVDhpeGtBUmtXQTI1bGRERWdNQjRHQ2dtU0pvbVQ4aXhrQVJrV0VHVnNaV04wY205dWFXTm9aV0ZzZEdneEVqQVFCZ29Ka2lhSmsvSXNaQUVaRmdKcFpERWdNQjRHQ2dtU0pvbVQ4aXhrQVJrV0VEZ3dNRE0yTWpNeU16TXpOamN4TURBeElEQWVCZ05WQkFvVEYxUmxjM1FnU0dWaGJIUm9JRk5sY25acFkyVWdOelV6TVR3d09nWURWUVFERXpOblpXNWxjbUZzTGpnd01ETTJNak15TXpNek5qY3hNREF1YVdRdVpXeGxZM1J5YjI1cFkyaGxZV3gwYUM1dVpYUXVZWFV3Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRQ3h0cUg0U1RuVjFhWWwzZU1rSVVMV25yODhucG92Zm56T0dWUFhpMUZncVFLUG9HQW9UU054R2tqUmxkUXNRQVRrbmoxSWRvNkxZS2IvdGZ2NGNoT3ZjSzRYSkdLSWRIV3FVSXE1VVZSalFTQ2VNUmlmK3Fzb0loZ1p2RjE5VFd6SWhMNEl1MTFzQUdNS1hSTi9EQmhmemhnNUJJR1dCSGhEYTQ1UWV6YUdIVHMvYmdIRE5oYzZmeUdDbXZNUnRndHBkSWtsNHlvVXVYbTVBeXhxSi9XeCtZSVdxVmdTbnI5TWxmRUsxZ1ZmNVZuakc5aGtlekR5VTF2OXlTWVdKbE9MNHlxRVB1WDlCRnF2anNqVFR5VTVrNU93RXU0NUoyMFBDTTJjazZuaXlBT3BJMGFhellpME5MQSswQU9zMlNFVXY0cDczVUx2bjZUNUs2R0JSNnQ3QWdNQkFBR2pnZ0tLTUlJQ2hqQU1CZ05WSFJNQkFmOEVBakFBTUV3R0NDc0dBUVVGQndFQkJFQXdQakE4QmdnckJnRUZCUWN3QVlZd2FIUjBjRG92TDIxaGRHVnpkRzlqYzNBdVkyVnlkR2xtYVdOaGRHVnpMV0YxYzNSeVlXeHBZUzVqYjIwdVlYVXZNSUlCSEFZRFZSMGdCSUlCRXpDQ0FROHdnZ0VMQmdvcUpOTCtnSGNCRkFFQk1JSDhNSUhMQmdnckJnRUZCUWNDQWpDQnZocUJ1ME5sY25ScFptbGpZWFJsY3lCcGMzTjFaV1FnZFc1a1pYSWdkR2hwY3lCRFVDQnRkWE4wSUc5dWJIa2dZbVVnY21Wc2FXVmtJRzl1SUdKNUlHVnVkR2wwYVdWeklIZHBkR2hwYmlCMGFHVWdRMjl0YlhWdWFYUjVJRzltSUVsdWRHVnlaWE4wTENCMWJteGxjM01nYjNSb1pYSjNhWE5sSUdGbmNtVmxaQ3dnWVc1a0lHNXZkQ0JtYjNJZ2NIVnljRzl6WlhNZ2IzUm9aWElnZEdoaGJpQjBhRzl6WlNCd1pYSnRhWFIwWldRZ1lua2dkR2hwY3lCRFVDNHdMQVlJS3dZQkJRVUhBZ0VXSUdoMGRIQTZMeTkzZDNjdWFIVnRZVzV6WlhKMmFXTmxjeTVuYjNZdVlYVXZNQmtHQ1Nva281Q1ZGd0hPR1FRTUZnbzNOVEF6TXpJMk1UVTBNRTBHQTFVZEVRUkdNRVNHUW1oMGRIQTZMeTl1Y3k1bGJHVmpkSEp2Ym1samFHVmhiSFJvTG01bGRDNWhkUzlwWkM5b2FTOUlVRWt0VHk4eExqQXZPREF3TXpZeU16SXpNek0yTnpFd01EQU9CZ05WSFE4QkFmOEVCQU1DQkxBd0h3WURWUjBqQkJnd0ZvQVVyMkRlZFdITFQyb3dvVGFUUmsxbE13Q0lyZTR3VGdZRFZSMGZCRWN3UlRCRG9FR2dQNFk5YUhSMGNEb3ZMMjFoZEdWemRDNWpaWEowYVdacFkyRjBaWE10WVhWemRISmhiR2xoTG1OdmJTNWhkUzlOUVU5RFFUSXZiR0YwWlhOMExtTnliREFkQmdOVkhRNEVGZ1FVUnY4SGc0c1BSRXpEcnphYXBNd05xRWNjNHQ0d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFCR3V5N0hRL2Y0bll6L2xkalpMckdpbXdETnM2Szlhc25ieWN5VzZaa2gvaDZtQXdjYzJ3RitYQUpuenFqVkJUcThIYnJkQi82Vzkrb0IvRGtaMEZBWkxDSUJXRlBmcGErcWswWklEaEtSWmd2aEZ6eWlyaDcrdDRiN1Jac0xPZHpkTzhOdnB6NnRBS2RoTFBBVnRnd2h5N1lIYjZZcGwrSFhKRTZZQm04YWlEcUVDMHcrdzc5Sk5YVVZUOHVGNkc0SzVJbisxS2wyMWFxS09uSHdXNk9tb09GRWVpZnJpYVZySGs3bEMxdjJRUUdOT2pVS1dKQ1BVNjFyNGFCT2ZqeVp6Yjc1TjdKdGF5ZUwzeDhKQ2o3Q1YvaFJHZ0x1d1hIeVVHZ3lsVGhRNlB1dHMvSlJlRFFrTG1HMkFYUVhQT3dCWkhOM3Y1WlNLajZKblkvNFJFME09Il19.eyJzdWIiOiIwIiwibmFtZSI6IlRlc3QgRG9jdG9yIE5hbWUiLCJwcm9maWxlIjoiaHR0cHM6Ly90ZXN0LmZoaXItZmFjYWRlLmxvY2FsaG9zdC9QcmFjdGl0aW9uZXIvMCIsImlzcyI6IlRlc3QgTWVkaWNhcmUgQXVzdHJhbGlhIE9yZ2FuaXNhdGlvbiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSIsImF1ZCI6Imh0dHBzOi8vZmhpcnRlc3QuZW1lcmdpbmcuY29tLmF1IiwiZXhwIjoxNjI2NjczODQ0LCJqdGkiOiJmZGRkODkyYzE1NjU0ODc5OTM5ZmViNGQyOTQ1ZjUyMCIsImlhdCI6MTYyNjY3MDE4NCwibmJmIjoxNjI2NjcwMTg0LCJwcm92aWRlck5vIjoiOTc2MTY2Q0giLCJpc0RlbGVnYXRlIjoiTiIsInJvbGVzIjpbIlByYWN0aXRpb25lciIsIlByYWN0aWNlTWFuYWdlciJdLCJwbXN2ZXIiOiJFeGFtcGxlIEVIUiB2MS4zNCIsInByYWN0aXRpb25lciI6IjAiLCJwcmFjdGl0aW9uZXJyb2xlIjoiZWZkMDE1NmZlMjNjNDM5ZDkwNDIyZWViNWMwMTM4Y2UiLCJvcmdhbml6YXRpb24iOiIwIn0.bSMu1hNCIhvFcPAeETDhQap95jXdgwPPZpN17qf35sqykHvZPVvVFmm6fIloZgccAfNWpd9YGHMTO33U4oq35VeyRXAhPMUrshQF5ozVDH6otSKRCHKiddMFzCiotNNe3RAmlS8m3vP28eSf325cPzPE4sddPqxxNUBgrIT0bFpNmSu3rBw4_Ql6MO_ZBFr2pnZak2FiFlzW6sU-XVEbJL5U8cBQ7YZhX4xF6PNEmdrY1zcVT5lHZwKgYOCziH1gK47_TuVbaGvTwpVqE6T3YuzCpUNllc_MW9kKtEslpqE6hz1YbRT4unuVa2SjpqHiM5nDwcw-e0TZ5uEeHPpwVA",
  "organization": "1655118",
  "practitioner": "1655119",
  "practitionerrole": "1655120"
}

The id_token within this response will be as described on the main AU profile page, so I won't repeat that here, but of note is that the id_token will be signed with the organization's NASH private certificate, so that this token can then be verified as being produced by that organization, and also access to the organization's HPI-O in the public certificate. In some cases, this can assist in the SMART applications internal authentication/registration models, with lowever up front configurations.

5 AU SMART App - retrieves some data from the PMS' FHIR API

From this point forward, until the expires_in period passes, the SMART application can call the PMS's FHIR API with the access token as a bearer token.

For example, retrieving the patient resource that is in context. Attempting to retrieve any other patient would be expected to return a 401 Unauthorized, or a 404 Not found depending on the PMS' internal security model, and an open search for patient's would likely just return this one patient record.

GET: https://ehr.example.com/Patient/1655118
Accept: application/fhir+xml
Authorization: Bearer m7rt6i7s9nuxkjvi8vsx

This would then return the Patient FHIR resource (in XML format).


Attachments: