Finnish Implementation Guide for SMART App Launch
1.0.0 - trial-use Finland flag

This page is part of the Finnish Implementation Guide for SMART App Launch (v1.0.0: STU 1) based on FHIR R4. This is the current published version. For a full list of available versions, see the Directory of published versions

Example AuditEvent: SMARTExampleApottiPractitionerEHR

An example in Apotti Ekosysteemi, launching the development version of the Sensotrend app (client).


Sensotrend’s app has been set up in the Epic on FHIR portal and the Client ID has been downloaded to Apotti, and a launch button has been configured in Apotti.

App Launch

When a practitioner clicks the Sensotrend button on the EHR, the EHR generates a launch request to the client:


The client app can use the iss parameter to decide whether to process the request at all. In this case we want to continue.

Server Metadata

In order to learn more about the system that is launching the app, the client app fetches the server metadata (based on the iss parameter and the .well-known location):


The response is:

  "authorization_endpoint": "https:\/\/\/Interconnect-FHIR-EKO01\/oauth2\/authorize",
  "token_endpoint": "https:\/\/\/Interconnect-FHIR-EKO01\/oauth2\/token",
  "token_endpoint_auth_methods_supported": ["client_secret_post", "client_secret_basic", "private_key_jwt"],
  "scopes_supported": ["epic.scanning.dmsusername", "fhirUser", "launch", "openid", "profile"],
  "response_types_supported": ["code"],
  "capabilities": [

The client app can cache this information and use a conditional request on subsequent launches to verify whether the information is still up to date (using the information present in the HTTP header of the above response).

Authorization Redirect

The client then redirects the launch request to the authorization endpoint. The request includes the scope, the redirect_url, and the client_id known to the client app. The request could also include the client secret, in case of a confidential app. Importantly, the client app sets a one time state parameter through which it can identify the redirect back from the auth server.


Authorization Response

The authorization server approves the request and redirects back to the indicated redirect_uri, together with the state parameter the client app issued, and a code that the client app can use to fetch the access token and context information.


Access Token Retrieval

The client app exchanges the code to access token and context information with a POST request to the token endpoint (retrieved earlier with the server metadata).

POST 'code=2Q7gMpAsZuZdJeRrQHsKF0JW9HxodF5CrFjWWihM9STOkCutWYPPG5dKGG6fuLe_5ddxgSoBH2coxAfeQW_CrKTSS02RXsoxXN8YZO2AIznbB4iiBQzQcEIs5mZ_-U6U&grant_type=authorization_code&' 

The response is:

  "access_token": "ODwdzFxnt2XPLkPN99X13HdgBy7v55nZuysW2RYbVQl9NnBVMuQv8ER5_3JDD1oPiRSp6EWS2LQ6Lv2GHtrSx2a8YHJRakSV1ZkvGVRN9YSAN7CaPA9GQ_Dc_0iS7MXe",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "user/ user/DocumentReference.write user/Encounter.Read user/ user/Observation.Read user/Observation.Write user/ user/Observation.write user/ user/Patient.Read user/ user/Practitioner.Read user/ user/ launch launch/patient openid",
  "state": "2c45ddb7-c830-4ef4-8922-7360b618768f",
  "__epic.dstu2.patient": "TsRGy4u8N.QB9ggWS-RNnKLIRbxmCIW4Fvyw1-8bXPawB",
  "deptID": "490771",
  "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImFlOHhRNTBiMFd3UGNmNjNYWENCcms4anFJUlErSVBwNTg0VlVLbmRwZXM9IiwidHlwIjoiSldUIn0.eyJhdWQiOiJiYTkzMmU3YS1kOWM5LTRkNzktYWY4Yi00ODE1OWE3MjdiMDEiLCJleHAiOjE2NzQ1NTYwNTQsImlhdCI6MTY3NDU1NTc1NCwiaXNzIjoiaHR0cHM6Ly9ndy5hcG90dGlla29zeXN0ZWVtaS5maS9JbnRlcmNvbm5lY3QtRkhJUi1FS08wMS9vYXV0aDIiLCJzdWIiOiJlaEhqcnJCbDJ1VWJDMC5vbG9DVFJVU2dqbzNjUGFaZVFaaHJiNDgxeWx4dzMifQ.ZL2NAp1g3BHMpJMdMn7IUOqhaBokSUjdc33k6UPYx-FA9TyAlneJDnxEJ8gVfRIck5Ix3zanyuBt0wOYOSfH160Jng54Qmhqgo_HRHHQzqoz-pS7jUd_LSrFpbrEKTBfsvrirhfExT9nGkzhPPMwfDzv5HSXR56WCljpXbPS9JkZv2NgQxc0PDEByPdFo_OH1icYa9z7b8Xq_MqwUG27bnDc3jzBTq9QBrQUO6jEYEJaZIc4KaakizHPzjYaf-Av39ZIiw2FnG59xawHEwP77xsYaOJA9sMwMeXvvshwlyN9EM152JbxjcYUWhJw07se-VRtKqI_f_O2BYp3Ly89KQ",
  "loginDepartment": "eYvrM0-vLt2R54-Oq4G7jgA3",
  "need_patient_banner": "true",
  "patient": "e5Lq8kpLjGQOrUOSyW1Bwwg3",
  "smart_style_url": ""

The parameters __epic.dstu2.patient, deptID, and loginDepartment are Epic specific parameters, the rest are defined by the SMART App Launch specification.

In this case, the client app uses the deptID to know the part of the organization the call comes from. The client app wants to limit the visibility of the app and the data to only specific clinics within Apotti.

The standard way to do this would be through the fhirContext parameter.

The client app can now use the access_token to fetch more information.

User Information

The client can decode the id_token to find out more about the person launching the app. It could be a patient, accessing the app through the patient portal, but in this case it is a practitioner.

The client app SHOULD verify the signature of the id_token. The public key required for verification can be found through the .well-known/openid-configuration, in this case with:


The client app can then use the key set uri from the jwks_uri property to validate the token.

An alternative is to use the token introspection endpoint.

Generated Narrative: AuditEvent

Resource AuditEvent "apotti-ehr-launch-by-practitioner"

type: User Authentication (Details: DICOM code 110114 = 'User Authentication', stated as 'User Authentication')

subtype: Application Start (Details: DICOM code 110120 = 'Application Start', stated as 'Application Start')

action: E

recorded: Jan 24, 2023, 12:20:18 PM


who: : Apotti Ekosysteemi

requestor: true


who: : Sensotrend Oy

requestor: false


*: Sensotrend OyWeb Server (Details: code 3 = 'Web Server', stated as 'Web Server')


Sensotrend’s client app manages patient-generated health data and therefore also manages the permissions that patients grant to different parties to access their data.

The details of that mechanism can be viewed in the video below. This video shows the above example in action. In this case the app is not launched from Apotti, rather from the Epic on FHIR portal.