Mini App Overview

Introduction

Superapps are comprehensive mobile or web applications that provide a wide range of services and functionalities within a single platform. These apps aim to become an ecosystem of various mini apps or features that users can access without leaving the main application. Here's an overview of mini apps in the context of superapps:

What are Mini Apps?

Mini apps are lightweight, sub-applications embedded within a superapp. They provide specific services or functionalities and can be developed by third-party developers or the superapp's team. These mini apps are designed to be fast, easy to use, and require minimal resources.

Benefits of Mini Apps in Superapps

  1. Convenience: Users can access multiple services without switching between different apps, saving time and effort.
  2. Enhanced User Engagement: A wide range of services keeps users engaged within the superapp, increasing user retention.
  3. Cross-Selling Opportunities: Superapps can cross-promote services within mini apps, boosting overall usage and revenue.
  4. Reduced Storage Space: Mini apps consume less storage space on users' devices compared to having multiple standalone apps.
  5. Streamlined Updates: Superapps can update mini apps independently, ensuring that users always have access to the latest features and improvements.

Objective

The objectives of mini apps within superapps are multifaceted, aiming to enhance user experience, Optimizing Resource Usage, and Enhancing Security and Compliance. Here are some key objectives:

  1. Enhancing User Convenience
  • Unified Access: Provide users with a one-stop platform where they can access multiple services without the need to download or switch between different apps.
  • Streamlined Experience: Simplify the user journey by integrating various functionalities within a single app, reducing the friction associated with using multiple standalone apps.
  1. Optimizing Resource Usage
  • Reduced Storage: Mini apps are lightweight, consuming less device storage and data compared to full-fledged apps, making them more accessible to users with limited resources.
  • Efficient Updates: Facilitate more efficient updates and maintenance, as mini apps can be updated independently without requiring users to update the entire superapp.
  1. Enhancing Security and Compliance
  • Centralized Management: Provide a secure and compliant environment for transactions and data management, ensuring user trust and safety.
  • Standardized Practices: Maintain high security and compliance standards across all mini apps within the superapp, protecting user data and privacy.

Interactive Launch Process

The following diagram illustrates the sequence of events when a superapp application is started.

figure-1

The authentication process begins with the user providing their credentials to the superapp. Once these credentials are verified and the superapp successfully authenticates the user, it generates a token. This token serves as proof of authentication and is securely stored in the session storage. When the user accesses a mini app, the superapp retrieves the token from the session storage and passes it to the mini app. The mini app then uses this token to confirm the user's authenticated status, allowing them to proceed with using the mini app without needing to re-enter their credentials. This streamlined process ensures a seamless and secure user experience across different components of the application ecosystem.


Launch Mini App

Launch Setup

In the Mini App launch flow, there are several essential items that must be in place to successfully open the mini app. Firstly, the authentication token generated by the superapp is critical. This token verifies the user's identity and ensures they have the necessary permissions to access the mini app. Secondly, a secure session storage mechanism is required to store and retrieve the token. This ensures that the token is available when the mini app is launched and that it remains secure throughout the session.

figure-2

figure-3

  1. Launch Request
Parameter Location Description
app_url Address The url of application to launch the program also Identifies as app url.
SMART_TOKEN Session Storage The payload of the token response typically contains several key pieces of information that are essential for the authentication and authorization process.
AUTH_URL Session Storage Issue url form identity server https://id.mobile.mhnexus.com/realms/person|
FHIR_URL Session Storage Fhir server endpoint to retrieve the data. https://veinscdr.mhnexus.com/baseR4|

A launch might cause the browser to navigate to:

  1. Template: {{app_url} } Session Storage : Payload of token
  2. Location: https://miniapp.mhnexus.com

Note: Please request to us for register the app URL to our server before development

  1. Credential Request
Key Value
token_url https://id.mobile.mhnexus.com/realms/person/protocol/openidconnect/token
client_id Person-portal
username haziq@mhnexus.com
password P@ssw0rd
grant_type P@ssw0rd
scope openid offline_access
Content-Type application/x-www-form-urlencoded
HTTP Method POST
Request

  curl --location 'https://id.mobile.mhnexus.com/realms/person/protocol/openidconnect/token' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'client_id=person-portal' \
  --data-urlencode 'username=haziq@mhnexus.com' \
  --data-urlencode 'password=P@ssw0rd' \
  --data-urlencode 'grant_type=password' \
  --data-urlencode 'scope=offline_access openid'   
  
Response

  {
  "access_token":
  "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ6S0dPWnBlZmFoNkJqTVl
  6VFA4MGZMSTBQM2JNb3pjVUVPWmpPMFpGT0c4In0.eyJleHAiOjE3MjA0ODI3O
  TgsImlhdCI6MTcyMDA1MDc5OCwianRpIjoiODdlZjdiOWYtMzllYS00NTc1LWIyN2It
  NWRhNDAzOTQwZGJkIiwiaXNzIjoiaHR0cHM6Ly9pZC5tb2JpbGUubWhuZXh1cy5j
  b20vcmVhbG1zL3BlcnNvbiIsInN1YiI6ImEyZGFhZmZmLWRhZDMtNGM4NS1iODY
  0LTcyNWNkNWJkOTg3NSIsInR5cCI6IkJlYXJlciIsImF6cCI6InBlcnNvbi1wb3J0YWwi
  LCJzZXNzaW9uX3N0YXRlIjoiMmI4M2NmMGEtYjk4My00NjMwLTliMjQtNjM4YWNi
  Njc1Y2ViIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIvKiIsImh0dHA6Ly9sb2
  NhbGhvc3Q6OTIwMCIsImh0dHA6Ly9sb2NhbGhvc3Q6NDEwMCIsImh0dHA6Ly8x
  OTIuODIuNjMuNTA6OTYwMCJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZGV
  mYXVsdC1yb2xlcy1tb2JpbGUiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3Jpe
  mF0aW9uIl19LCJzY29wZSI6Im9wZW5pZCBvZmZsaW5lX2FjY2VzcyBwcm9maWxl
  IGVtYWlsIiwic2lkIjoiMmI4M2NmMGEtYjk4My00NjMwLTliMjQtNjM4YWNiNjc1Y2ViIi
  wiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwaG9uZU51bWJlciI6Iis2MDEzNjA1N
  Tg1MCIsIm5hbWUiOiJBaG1hZCBBaW1hbiBIYXppcSBBaG1hZCB0YXJtaWR6aSIs
  InByZWZlcnJlZF91c2VybmFtZSI6ImhhemlxQG1obmV4dXMuY29tIiwiZ2l2ZW5fbmF
  tZSI6IkFobWFkIEFpbWFuIEhhemlxIiwiaWRObyI6Ijk1MDcyODEwNjA1MSIsImZhb
  WlseV9uYW1lIjoiQWhtYWQgdGFybWlkemkiLCJlbWFpbCI6ImhhemlxQG1obmV4d
  XMuY29tIn0.P88t2URlsQjDNBARuUiMWurPZXUlN7pQ36_fDMiDWwluOuQSFyd6PIJmXNhtL5zTWHuJhjOEmRfNt
  R3O5_vSHs5g3on_l1Cat2pAqa9CJ1x1ZFWx73NcHCD4--
  S9O9LTQZrK_g5yWj1PGIVs8blmLxszXTye7Y8xKbJCMtVsoknysEO3JnaJtdmF9Ju
  UBNCAxDbtVCY88g19fFwfyknILrFBqaumFDVuBOaPPdqXDAYUs5Itwgm5DsSrk_Qj6bNs3T7yWqywDxKqXh4gXdoMVmclFIr8kNbQthTQSHZdMZ8Y_-
  Hunopa6eTnD3AwkXiMC20a9ckmVD2Gmt-4d6aA",
  "expires_in": 432000,
  "refresh_expires_in": 0,
  "refresh_token":
  "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIxZmM4NjQwYi1lYjk1LTQ3N
  DAtYjliYi04YTNlMjQxZjNkMzQifQ.eyJpYXQiOjE3MjAwNTA3OTgsImp0aSI6IjdhZW
  FiMmNiLThhMWMtNDAxNS04MjM0LWU4OGNhOTFmNjE1NSIsImlzcyI6Imh0dHBz
  Oi8vaWQubW9iaWxlLm1obmV4dXMuY29tL3JlYWxtcy9wZXJzb24iLCJhdWQiOiJod
  HRwczovL2lkLm1vYmlsZS5taG5leHVzLmNvbS9yZWFsbXMvcGVyc29uIiwic3ViIjoi
  YTJkYWFmZmYtZGFkMy00Yzg1LWI4NjQtNzI1Y2Q1YmQ5ODc1IiwidHlwIjoiT2Zm
  bGluZSIsImF6cCI6InBlcnNvbi1wb3J0YWwiLCJzZXNzaW9uX3N0YXRlIjoiMmI4M2
  NmMGEtYjk4My00NjMwLTliMjQtNjM4YWNiNjc1Y2ViIiwic2NvcGUiOiJvcGVuaWQg
  b2ZmbGluZV9hY2Nlc3MgcHJvZmlsZSBlbWFpbCIsInNpZCI6IjJiODNjZjBhLWI5OD
  MtNDYzMC05YjI0LTYzOGFjYjY3NWNlYiJ9.js70UreVyChsOReT6rlY9X62aySG26j
  Om5RJuYnohkE",
  "token_type": "Bearer",
  "id_token":
  "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ6S0dPWnBlZmFoNkJqTVl
  6VFA4MGZMSTBQM2JNb3pjVUVPWmpPMFpGT0c4In0.eyJleHAiOjE3MjA0ODI3O
  TgsImlhdCI6MTcyMDA1MDc5OCwiYXV0aF90aW1lIjowLCJqdGkiOiI3YWI4MWY3Z
  S1jM2ExLTQ0NzEtYmJhNC1kZjQ1NmMxZGIyMTUiLCJpc3MiOiJodHRwczovL2lkL
  m1vYmlsZS5taG5leHVzLmNvbS9yZWFsbXMvcGVyc29uIiwiYXVkIjoicGVyc29uLXB
  vcnRhbCIsInN1YiI6ImEyZGFhZmZmLWRhZDMtNGM4NS1iODY0LTcyNWNkNWJk
  OTg3NSIsInR5cCI6IklEIiwiYXpwIjoicGVyc29uLXBvcnRhbCIsInNlc3Npb25fc3RhdG
  UiOiIyYjgzY2YwYS1iOTgzLTQ2MzAtOWIyNC02MzhhY2I2NzVjZWIiLCJhdF9oYXN
  oIjoia3FVTW9Kdi16eW5EZ2VkbkZ0bVB4dyIsImFjciI6IjEiLCJzaWQiOiIyYjgzY2YwY
  S1iOTgzLTQ2MzAtOWIyNC02MzhhY2I2NzVjZWIiLCJlbWFpbF92ZXJpZmllZCI6Zm
  Fsc2UsInBob25lTnVtYmVyIjoiKzYwMTM2MDU1ODUwIiwibmFtZSI6IkFobWFkIEFp
  bWFuIEhhemlxIEFobWFkIHRhcm1pZHppIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiaG
  F6aXFAbWhuZXh1cy5jb20iLCJnaXZlbl9uYW1lIjoiQWhtYWQgQWltYW4gSGF6aXE
  iLCJpZE5vIjoiOTUwNzI4MTA2MDUxIiwiZmFtaWx5X25hbWUiOiJBaG1hZCB0YXJt
  aWR6aSIsImVtYWlsIjoiaGF6aXFAbWhuZXh1cy5jb20ifQ.PwPXOVLHAY27n240xTHMA33xIQNnFOpoT7oH2g6DrX3W28qXmhqvnX55cGLsrrUnfzMB4ai0HJET
  FqB9dX9rEThyXxMwoi4phZ1xdAh2MRSl4GphXiMcKWxSnf57j_kX4g4bLUb7ui7CT
  d1pN8hJdo_S-F9MZ74gAponmfjmWIpXcX5LCNkbmZUltuNPkEWBtyhvv7EjlurtH2xjy7O_ie2LI05LF5ga
  IpjL6QY5n41o_QiEonTpb79Sh4B_sf3UW4p0-1vNGyC7UIP2ctyZL2mPqjangwbrjjvOuUsw0uqqOgjOleiGC-RNPgOsL6eoMkZeWyX56IkF8bnAMUQ",
  "not-before-policy": 0,
  "session_state": "2b83cf0a-b983-4630-9b24-638acb675ceb",
  "scope": "openid offline_access profile email"
  }
    

  1. Refresh Token Request
Key Value
token_url https://id.mobile.mhnexus.com/realms/person/protocol/openidconnect/token|
client_id Person-portal
refresh_token {{refresh_token} }
grant_type refresh_token
scope openid offline_access
Content-Type application/x-www-form-urlencoded
HTTP Method POST
Request

  curl --location 'https://veinssso.mhnexus.com/realms/person/protocol/openidconnect/token' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'client_id=person-portal' \
  --data-urlencode 'grant_type=refresh_token' \
  --data-urlencode
  'refresh_token=eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI4OWU4ZjEy
  Yy1iY2ZhLTRmNGItOTU3Ny03NTQ1MDE0MTk3M2EifQ.eyJleHAiOjE3MjAwMTc2
  MTgsImlhdCI6MTcyMDAxNzMxOCwianRpIjoiY2RiMTMzYjUtYzlhMi00N2ZlLWI3Y
  WQtYmIxMWRjNTlhNDYzIiwiaXNzIjoiaHR0cHM6Ly92ZWluc3Nzby5taG5leHVzLm
  NvbS9yZWFsbXMvcGVyc29uIiwiYXVkIjoiaHR0cHM6Ly92ZWluc3Nzby5taG5leHVz
  LmNvbS9yZWFsbXMvcGVyc29uIiwic3ViIjoiM2JhMjExOTAtMmQwZC00NmNhLTg0
  NjktMDI4YjBmYTIwNTZjIiwidHlwIjoiUmVmcmVzaCIsImF6cCI6InBlcnNvbi1wb3J0Y
  WwiLCJzZXNzaW9uX3N0YXRlIjoiNTZhNTc3OGQtZGQwMy00MzJiLTg5Y2QtNTRi
  MWI3MDAyNDIzIiwic2NvcGUiOiJsYXVuY2gvcGF0aWVudCBzc28tb3BlbmlkLWNvb
  m5lY3QgcGF0aWVudC8qLndyaXRlIGVtYWlsIHBhdGllbnQvKi5yZWFkIHByb2ZpbG
  UiLCJzaWQiOiI1NmE1Nzc4ZC1kZDAzLTQzMmItODljZC01NGIxYjcwMDI0MjMifQ.
  7wEDJazB_W2AKM2h8HweMcxKJ8PVGMtmGV5pNZMj-To'
    
Response

  {
  "access_token":
  "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ6S0dPWnBlZmFoNkJqTVl
  6VFA4MGZMSTBQM2JNb3pjVUVPWmpPMFpGT0c4In0.eyJleHAiOjE3MjA1MDMy
  ODIsImlhdCI6MTcyMDA3MTI4MiwianRpIjoiM2VjODA0YWQtZmZiOS00Zjk2LTgwZ
  DctZDFiMmZhZWIzZjk4IiwiaXNzIjoiaHR0cHM6Ly9pZC5tb2JpbGUubWhuZXh1cy5j
  b20vcmVhbG1zL3BlcnNvbiIsInN1YiI6ImEyZGFhZmZmLWRhZDMtNGM4NS1iODY
  0LTcyNWNkNWJkOTg3NSIsInR5cCI6IkJlYXJlciIsImF6cCI6InBlcnNvbi1wb3J0YWwi
  LCJzZXNzaW9uX3N0YXRlIjoiNzU4MDM4OTAtZGZiMy00MmQ4LTljMTktOGFhMz
  U3MmQ4MzI0IiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIvKiIsImh0dHA6Ly
  9sb2NhbGhvc3Q6OTIwMCIsImh0dHA6Ly9sb2NhbGhvc3Q6NDEwMCIsImh0dHA6
  Ly8xOTIuODIuNjMuNTA6OTYwMCJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsi
  ZGVmYXVsdC1yb2xlcy1tb2JpbGUiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3
  JpemF0aW9uIl19LCJzY29wZSI6Im9wZW5pZCBvZmZsaW5lX2FjY2VzcyBwcm9ma
  WxlIGVtYWlsIiwic2lkIjoiNzU4MDM4OTAtZGZiMy00MmQ4LTljMTktOGFhMzU3Mm
  Q4MzI0IiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwaG9uZU51bWJlciI6Iis2MD
  EzNjA1NTg1MCIsIm5hbWUiOiJBaG1hZCBBaW1hbiBIYXppcSBBaG1hZCB0YXJta
  WR6aSIsInByZWZlcnJlZF91c2VybmFtZSI6ImhhemlxQG1obmV4dXMuY29tIiwiZ2l2
  ZW5fbmFtZSI6IkFobWFkIEFpbWFuIEhhemlxIiwiaWRObyI6Ijk1MDcyODEwNjA1MS
  IsImZhbWlseV9uYW1lIjoiQWhtYWQgdGFybWlkemkiLCJlbWFpbCI6ImhhemlxQG1
  obmV4dXMuY29tIn0.hwJtzgMcCLyyu31FrRTF2DsnLdzIxwqgWsnC3PtotXQ3OiUKgbLxIRcJn1yn185Dkh2zMJf7j4CEdD2oYJTYjBU1PO6TvePJsoRx2sF9Xo
  ij_VgHigDQiJ9U_7f2vh0gXFA0hZzwwkyxqP-vOJWb_hcj1MF2wuF1T8VBVEhdYRi2meGkY2lyDiI9RxSEjBMgYNMlC2YFJQG3AptJs6l_hvUbl7YhWDEePOsvqCWvn7Wudp_hXJlEdm5
  PX2G1Q5_QGfTk9fZ6lLybuT3SUHFttrAdoKNEzGOzekzr6Wj--
  CZFrSdBbxmy5lxNe7EYxxzS1rq5k6BXv9n_2sNQrCg",
  "expires_in": 432000,
  "refresh_expires_in": 0,
  "refresh_token":
  "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIxZmM4NjQwYi1lYjk1LTQ3N
  DAtYjliYi04YTNlMjQxZjNkMzQifQ.eyJpYXQiOjE3MjAwNzEyODIsImp0aSI6ImEzMT
  g2YWM3LTA0N2QtNDY1Ny04YTUyLWM5MmM5MWMzOWY0ZCIsImlzcyI6Imh0d
  HBzOi8vaWQubW9iaWxlLm1obmV4dXMuY29tL3JlYWxtcy9wZXJzb24iLCJhdWQi
  OiJodHRwczovL2lkLm1vYmlsZS5taG5leHVzLmNvbS9yZWFsbXMvcGVyc29uIiwic3
  ViIjoiYTJkYWFmZmYtZGFkMy00Yzg1LWI4NjQtNzI1Y2Q1YmQ5ODc1IiwidHlwIjoiT
  2ZmbGluZSIsImF6cCI6InBlcnNvbi1wb3J0YWwiLCJzZXNzaW9uX3N0YXRlIjoiNzU4
  MDM4OTAtZGZiMy00MmQ4LTljMTktOGFhMzU3MmQ4MzI0Iiwic2NvcGUiOiJvcGV
  uaWQgb2ZmbGluZV9hY2Nlc3MgcHJvZmlsZSBlbWFpbCIsInNpZCI6Ijc1ODAzODk
  wLWRmYjMtNDJkOC05YzE5LThhYTM1NzJkODMyNCJ9._uTxE_WHvYEBF6IfWk
  naj7KNdJ5E479ukSYIu4sKsNg",
  "token_type": "Bearer",
  "id_token":
  "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ6S0dPWnBlZmFoNkJqTVl
  6VFA4MGZMSTBQM2JNb3pjVUVPWmpPMFpGT0c4In0.eyJleHAiOjE3MjA1MDMy
  ODIsImlhdCI6MTcyMDA3MTI4MiwiYXV0aF90aW1lIjowLCJqdGkiOiIwMmI5N2QxZ
  C1hN2EzLTRhODMtOTZmYS0yZThlN2FmMGRmNjAiLCJpc3MiOiJodHRwczovL2l
  kLm1vYmlsZS5taG5leHVzLmNvbS9yZWFsbXMvcGVyc29uIiwiYXVkIjoicGVyc29uL
  XBvcnRhbCIsInN1YiI6ImEyZGFhZmZmLWRhZDMtNGM4NS1iODY0LTcyNWNkN
  WJkOTg3NSIsInR5cCI6IklEIiwiYXpwIjoicGVyc29uLXBvcnRhbCIsInNlc3Npb25fc3R
  hdGUiOiI3NTgwMzg5MC1kZmIzLTQyZDgtOWMxOS04YWEzNTcyZDgzMjQiLCJhd
  F9oYXNoIjoiUkhfSTN1U2F4T2JpOFJiMjdnRHJOQSIsImFjciI6IjEiLCJzaWQiOiI3NT
  gwMzg5MC1kZmIzLTQyZDgtOWMxOS04YWEzNTcyZDgzMjQiLCJlbWFpbF92ZXJ
  pZmllZCI6ZmFsc2UsInBob25lTnVtYmVyIjoiKzYwMTM2MDU1ODUwIiwibmFtZSI6Ik
  FobWFkIEFpbWFuIEhhemlxIEFobWFkIHRhcm1pZHppIiwicHJlZmVycmVkX3VzZXJ
  uYW1lIjoiaGF6aXFAbWhuZXh1cy5jb20iLCJnaXZlbl9uYW1lIjoiQWhtYWQgQWltYW
  4gSGF6aXEiLCJpZE5vIjoiOTUwNzI4MTA2MDUxIiwiZmFtaWx5X25hbWUiOiJBaG1
  hZCB0YXJtaWR6aSIsImVtYWlsIjoiaGF6aXFAbWhuZXh1cy5jb20ifQ.G_PbgGb91W
  wa28AYW84pewpRRGvcej4eYd5-v3-
  X8iQmSirvbhIDuIvEhUPglR7dKSaQ4KwxkhOgksYHBE4PiPMg8MCw0kjfl1MSebfMuXGru7HaItJoLaHZ2JP9ibzuStEHp1yXHzMRpA47RvC
  Ly5DrELsGM4p5Knx1O0E22Gg0hA2mEPv2bkJxM275Wswky_xVxmKUMCQdZCc3QDkRa-xPypAzOeAT0h9fnpcM7EmPYJLVQvBHAPZebOCnINTXj1Xt697ul78s8a59Xk2oWVCu0VPYo
  Wcpu6O5D75D6azOvCfZUt8s6Pr2FTowUOoNThj8V_wJR-_qvfNaXCg",
  "not-before-policy": 1720051279,
  "session_state": "75803890-dfb3-42d8-9c19-8aa3572d8324",
  "scope": "openid offline_access profile email"
  }
    

  1. UserInfo Request
Key Value
url https://id.mobile.mhnexus.com/realms/person/protocol/openidconnect/userinfo
Authorization Bearer {{access_token} }
HTTP Method GET
Request

  curl --location 'https://id.mobile.mhnexus.com/realms/person/protocol/openidconnect/userinfo' \
  --header 'Authorization: Bearer
  eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ6S0dPWnBlZmFoNkJqTVl6
  VFA4MGZMSTBQM2JNb3pjVUVPWmpPMFpGT0c4In0.eyJleHAiOjE3MjA0ODI3O
  TgsImlhdCI6MTcyMDA1MDc5OCwianRpIjoiODdlZjdiOWYtMzllYS00NTc1LWIyN2It
  NWRhNDAzOTQwZGJkIiwiaXNzIjoiaHR0cHM6Ly9pZC5tb2JpbGUubWhuZXh1cy5j
  b20vcmVhbG1zL3BlcnNvbiIsInN1YiI6ImEyZGFhZmZmLWRhZDMtNGM4NS1iODY
  0LTcyNWNkNWJkOTg3NSIsInR5cCI6IkJlYXJlciIsImF6cCI6InBlcnNvbi1wb3J0YWwi
  LCJzZXNzaW9uX3N0YXRlIjoiMmI4M2NmMGEtYjk4My00NjMwLTliMjQtNjM4YWNi
  Njc1Y2ViIiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIvKiIsImh0dHA6Ly9sb2
  NhbGhvc3Q6OTIwMCIsImh0dHA6Ly9sb2NhbGhvc3Q6NDEwMCIsImh0dHA6Ly8x
  OTIuODIuNjMuNTA6OTYwMCJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZGV
  mYXVsdC1yb2xlcy1tb2JpbGUiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3Jpe
  mF0aW9uIl19LCJzY29wZSI6Im9wZW5pZCBvZmZsaW5lX2FjY2VzcyBwcm9maWxl
  IGVtYWlsIiwic2lkIjoiMmI4M2NmMGEtYjk4My00NjMwLTliMjQtNjM4YWNiNjc1Y2ViIi
  wiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwaG9uZU51bWJlciI6Iis2MDEzNjA1N
  Tg1MCIsIm5hbWUiOiJBaG1hZCBBaW1hbiBIYXppcSBBaG1hZCB0YXJtaWR6aSIs
  InByZWZlcnJlZF91c2VybmFtZSI6ImhhemlxQG1obmV4dXMuY29tIiwiZ2l2ZW5fbmF
  tZSI6IkFobWFkIEFpbWFuIEhhemlxIiwiaWRObyI6Ijk1MDcyODEwNjA1MSIsImZhb
  WlseV9uYW1lIjoiQWhtYWQgdGFybWlkemkiLCJlbWFpbCI6ImhhemlxQG1obmV4d
  XMuY29tIn0.P88t2URlsQjDNBARuUiMWurPZXUlN7pQ36_fDMiDWwluOuQSFyd6PIJmXNhtL5zTWHuJhjOEmRfNt
  R3O5_vSHs5g3on_l1Cat2pAqa9CJ1x1ZFWx73NcHCD4--
  S9O9LTQZrK_g5yWj1PGIVs8blmLxszXTye7Y8xKbJCMtVsoknysEO3JnaJtdmF9Ju
  UBNCAxDbtVCY88g19fFwfyknILrFBqaumFDVuBOaPPdqXDAYUs5Itwgm5DsSrk_Qj6bNs3T7yWqywDxKqXh4gXdoMVmclFIr8kNbQthTQSHZdMZ8Y_-
  Hunopa6eTnD3AwkXiMC20a9ckmVD2Gmt-4d6aA'
    
Response

  {
  "access_token":
  "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ6S0dPWnBlZmFoNkJqTVl
  6VFA4MGZMSTBQM2JNb3pjVUVPWmpPMFpGT0c4In0.eyJleHAiOjE3MjA1MDMy
  ODIsImlhdCI6MTcyMDA3MTI4MiwianRpIjoiM2VjODA0YWQtZmZiOS00Zjk2LTgwZ
  DctZDFiMmZhZWIzZjk4IiwiaXNzIjoiaHR0cHM6Ly9pZC5tb2JpbGUubWhuZXh1cy5j
  b20vcmVhbG1zL3BlcnNvbiIsInN1YiI6ImEyZGFhZmZmLWRhZDMtNGM4NS1iODY
  0LTcyNWNkNWJkOTg3NSIsInR5cCI6IkJlYXJlciIsImF6cCI6InBlcnNvbi1wb3J0YWwi
  LCJzZXNzaW9uX3N0YXRlIjoiNzU4MDM4OTAtZGZiMy00MmQ4LTljMTktOGFhMz
  U3MmQ4MzI0IiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIvKiIsImh0dHA6Ly
  9sb2NhbGhvc3Q6OTIwMCIsImh0dHA6Ly9sb2NhbGhvc3Q6NDEwMCIsImh0dHA6
  Ly8xOTIuODIuNjMuNTA6OTYwMCJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsi
  ZGVmYXVsdC1yb2xlcy1tb2JpbGUiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3
  JpemF0aW9uIl19LCJzY29wZSI6Im9wZW5pZCBvZmZsaW5lX2FjY2VzcyBwcm9ma
  WxlIGVtYWlsIiwic2lkIjoiNzU4MDM4OTAtZGZiMy00MmQ4LTljMTktOGFhMzU3Mm
  Q4MzI0IiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwaG9uZU51bWJlciI6Iis2MD
  EzNjA1NTg1MCIsIm5hbWUiOiJBaG1hZCBBaW1hbiBIYXppcSBBaG1hZCB0YXJta
  WR6aSIsInByZWZlcnJlZF91c2VybmFtZSI6ImhhemlxQG1obmV4dXMuY29tIiwiZ2l2
  ZW5fbmFtZSI6IkFobWFkIEFpbWFuIEhhemlxIiwiaWRObyI6Ijk1MDcyODEwNjA1MS
  IsImZhbWlseV9uYW1lIjoiQWhtYWQgdGFybWlkemkiLCJlbWFpbCI6ImhhemlxQG1
  obmV4dXMuY29tIn0.hwJtzgMcCLyyu31FrRTF2DsnLdzIxwqgWsnC3PtotXQ3OiUKgbLxIRcJn1yn185Dkh2zMJf7j4CEdD2oYJTYjBU1PO6TvePJsoRx2sF9Xo
  ij_VgHigDQiJ9U_7f2vh0gXFA0hZzwwkyxqP-vOJWb_hcj1MF2wuF1T8VBVEhdYRi2meGkY2lyDiI9RxSEjBMgYNMlC2YFJQG3AptJs6l_hvUbl7YhWDEePOsvqCWvn7Wudp_hXJlEdm5
  PX2G1Q5_QGfTk9fZ6lLybuT3SUHFttrAdoKNEzGOzekzr6Wj--
  CZFrSdBbxmy5lxNe7EYxxzS1rq5k6BXv9n_2sNQrCg",
  "expires_in": 432000,
  "refresh_expires_in": 0,
  "refresh_token":
  "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIxZmM4NjQwYi1lYjk1LTQ3N
  DAtYjliYi04YTNlMjQxZjNkMzQifQ.eyJpYXQiOjE3MjAwNzEyODIsImp0aSI6ImEzMT
  g2YWM3LTA0N2QtNDY1Ny04YTUyLWM5MmM5MWMzOWY0ZCIsImlzcyI6Imh0d
  HBzOi8vaWQubW9iaWxlLm1obmV4dXMuY29tL3JlYWxtcy9wZXJzb24iLCJhdWQi
  OiJodHRwczovL2lkLm1vYmlsZS5taG5leHVzLmNvbS9yZWFsbXMvcGVyc29uIiwic3
  ViIjoiYTJkYWFmZmYtZGFkMy00Yzg1LWI4NjQtNzI1Y2Q1YmQ5ODc1IiwidHlwIjoiT
  2ZmbGluZSIsImF6cCI6InBlcnNvbi1wb3J0YWwiLCJzZXNzaW9uX3N0YXRlIjoiNzU4
  MDM4OTAtZGZiMy00MmQ4LTljMTktOGFhMzU3MmQ4MzI0Iiwic2NvcGUiOiJvcGV
  uaWQgb2ZmbGluZV9hY2Nlc3MgcHJvZmlsZSBlbWFpbCIsInNpZCI6Ijc1ODAzODk
  wLWRmYjMtNDJkOC05YzE5LThhYTM1NzJkODMyNCJ9._uTxE_WHvYEBF6IfWk
  naj7KNdJ5E479ukSYIu4sKsNg",
  "token_type": "Bearer",
  "id_token":
  "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ6S0dPWnBlZmFoNkJqTVl
  6VFA4MGZMSTBQM2JNb3pjVUVPWmpPMFpGT0c4In0.eyJleHAiOjE3MjA1MDMy
  ODIsImlhdCI6MTcyMDA3MTI4MiwiYXV0aF90aW1lIjowLCJqdGkiOiIwMmI5N2QxZ
  C1hN2EzLTRhODMtOTZmYS0yZThlN2FmMGRmNjAiLCJpc3MiOiJodHRwczovL2l
  kLm1vYmlsZS5taG5leHVzLmNvbS9yZWFsbXMvcGVyc29uIiwiYXVkIjoicGVyc29uL
  XBvcnRhbCIsInN1YiI6ImEyZGFhZmZmLWRhZDMtNGM4NS1iODY0LTcyNWNkN
  WJkOTg3NSIsInR5cCI6IklEIiwiYXpwIjoicGVyc29uLXBvcnRhbCIsInNlc3Npb25fc3R
  hdGUiOiI3NTgwMzg5MC1kZmIzLTQyZDgtOWMxOS04YWEzNTcyZDgzMjQiLCJhd
  F9oYXNoIjoiUkhfSTN1U2F4T2JpOFJiMjdnRHJOQSIsImFjciI6IjEiLCJzaWQiOiI3NT
  gwMzg5MC1kZmIzLTQyZDgtOWMxOS04YWEzNTcyZDgzMjQiLCJlbWFpbF92ZXJ
  pZmllZCI6ZmFsc2UsInBob25lTnVtYmVyIjoiKzYwMTM2MDU1ODUwIiwibmFtZSI6Ik
  FobWFkIEFpbWFuIEhhemlxIEFobWFkIHRhcm1pZHppIiwicHJlZmVycmVkX3VzZXJ
  uYW1lIjoiaGF6aXFAbWhuZXh1cy5jb20iLCJnaXZlbl9uYW1lIjoiQWhtYWQgQWltYW
  4gSGF6aXEiLCJpZE5vIjoiOTUwNzI4MTA2MDUxIiwiZmFtaWx5X25hbWUiOiJBaG1
  hZCB0YXJtaWR6aSIsImVtYWlsIjoiaGF6aXFAbWhuZXh1cy5jb20ifQ.G_PbgGb91W
  wa28AYW84pewpRRGvcej4eYd5-v3-
  X8iQmSirvbhIDuIvEhUPglR7dKSaQ4KwxkhOgksYHBE4PiPMg8MCw0kjfl1MSebfMuXGru7HaItJoLaHZ2JP9ibzuStEHp1yXHzMRpA47RvC
  Ly5DrELsGM4p5Knx1O0E22Gg0hA2mEPv2bkJxM275Wswky_xVxmKUMCQdZCc3QDkRa-xPypAzOeAT0h9fnpcM7EmPYJLVQvBHAPZebOCnINTXj1Xt697ul78s8a59Xk2oWVCu0VPYo
  Wcpu6O5D75D6azOvCfZUt8s6Pr2FTowUOoNThj8V_wJR-_qvfNaXCg",
  "not-before-policy": 1720051279,
  "session_state": "75803890-dfb3-42d8-9c19-8aa3572d8324",
  "scope": "openid offline_access profile email"
  }
    

  1. Patient data request
Key Value
url https://veinscdr.mhnexus.com/baseR4/Patient/74c778d4-19a4-442e-8918-620733047fce
Authorization Bearer {{access_token} }
HTTP Method GET
Request

  curl --location 'https://veinscdr.mhnexus.com/baseR4/Patient/74c778d4-19a4-442e8918-620733047fce' \
  --header 'Authorization: ••••••'
    
Response

  {
  "resourceType": "Patient",
  "id": "74c778d4-19a4-442e-8918-620733047fce",
  "meta": {
  "versionId": "6",
  "lastUpdated": "2024-05-21T20:04:25.955+08:00",
  "source": "http://provider.hie.moh.gov.my#TfYivuSnxXRxzgqB",
  "profile": [
  "http://fhir.hie.moh.gov.my/StructureDefinition/Patient-my-core"
  ]
  },
  "extension": [
  {
  "url": "http://fhir.hie.moh.gov.my/StructureDefinition/person-category-army-my-core",
  "valueCodeableConcept": {
  "coding": [
  {
  "system": "http://fhir.hie.moh.gov.my/CodeSystem/person-category-army-my-core",
  "code": "04",
  "display": "Awam"
  }
  ]
  }
  },
  {
  "url": "http://fhir.hie.moh.gov.my/StructureDefinition/ethnic-my-core",
  "valueCodeableConcept": {
  "coding": [
  {
  "system": "http://fhir.hie.moh.gov.my/CodeSystem/ethnic-my-core",
  "code": "01",
  "display": "Melayu"
  }
  ]
  }
  },
  {
  "url": "http://fhir.hie.moh.gov.my/StructureDefinition/citizenship-my-core",
  "extension": [
  {
  "url": "citizenship",
  "valueBoolean": true
  }
  ]
  },
  {
  "url": "http://fhir.hie.moh.gov.my/StructureDefinition/audit-my-core",
  "extension": [
  {
  "url": "recorder",
  "valueReference": {
  "reference": "PractitionerRole/880c2474-35fb-4d66-881a-a02c4a00e611/_history/1",
  "display": "SITI KASTURI"
  }
  },
  {
  "url": "recordedDate",
  "valueDateTime": "2022-12-21T10:03:58+08:00"
  },
  {
  "url": "lastUpdater",
  "valueReference": {
  "reference": "PractitionerRole/ca8ce33d-89c7-479e-a807-
  a4b621b3074a/_history/3",
  "display": "SAIFULDAULAH BIN MOHD HAFIZ NGOO"
  }
  }
  ]
  }
  ],
  "identifier": [
  {
  "use": "official",
  "system": "http://fhir.hie.moh.gov.my/sid/my-kad-no",
  "value": "950728106051"
  },
  {
  "use": "official",
  "system": "http://fhir.hie.moh.gov.my/sid/patient-mrn",
  "value": "HIE-00000305"
  }
  ],
  "active": true,
  "name": [
  {
  "extension": [
  {
  "url": "http://fhir.hie.moh.gov.my/StructureDefinition/person-title-my-core",
  "valueCodeableConcept": {
  "coding": [
  {
  "system": "http://fhir.hie.moh.gov.my/CodeSystem/person-title-my-core",
  "code": "C011",
  "display": "Tan Sri Dr"
  }
  ]
  }
  }
  ],
  "use": "official",
  "text": "AHMAD AIMAN HAZIQ BIN AHMAD TARMIDZI",
  "given": [
  "AHMAD AIMAN HAZIQ BIN AHMAD TARMIDZI"
  ]
  }
  ],
  "telecom": [
  {
  "system": "phone",
  "value": "0136055850",
  "use": "mobile"
  }
  ],
  "gender": "male",
  "birthDate": "1995-07-28",
  "deceasedBoolean": false,
  "address": [
  {
  "extension": [
  {
  "url": "http://fhir.hie.moh.gov.my/StructureDefinition/address-district-my-core",
  "valueCodeableConcept": {
  "coding": [
  {
  "system": "http://fhir.hie.moh.gov.my/CodeSystem/district-my-core",
  "code": "1401",
  "display": "W.P. Kuala Lumpur"
  }
  ]
  }
  },
  {
  "url": "http://fhir.hie.moh.gov.my/StructureDefinition/address-state-my-core",
  "valueCodeableConcept": {
  "coding": [
  {
  "system": "http://fhir.hie.moh.gov.my/CodeSystem/state-my-core",
  "code": "14",
  "display": "Wilayah Persekutuan Kuala Lumpur"
  }
  ]
  }
  }
  ],
  "line": [
  "T3 TOWER 3"
  ],
  "city": "AMPANG",
  "postalCode": "50600",
  "country": "MYS"
  }
  ],
  "managingOrganization": {
  "reference": "Organization/SDHH"
  }
  }
    


Mini App Development

  1. Creating the App Creating a basic Progressive Web App (PWA) with login and home pages using JavaScript involves several steps. Here is a simple example to get you started. Your project structure will look something like this:

Mini-app/
│
├── index.html
├── login.html
├── home.html
├── package.json
  1. Creating login page This page will contain a simple login form. In this section the response of the payload will store inside session storage.
  • hightlight : sessionStorage.setItem('SMART_TOKEN', JSON.stringify(result));
Code Snippet

  
  <form id="loginForm">
  <h2>Login</h2>
  <hr>
  </hr>
  <label for="username">Username:</label>
  <input type="text" id="username" name="username" required />
  <br />
  <label for="password">Password:</label>
  <input type="password" id="password" name="password" required />
  <br />
  <button type="submit">Login</button>
  </form>
  <script type="text/javascript">
  document.getElementById('loginForm').addEventListener('submit', function (event)
  {
  event.preventDefault(); // Prevent the form from submitting the traditional way
  const username = document.getElementById('username').value;
  const password = document.getElementById('password').value;
  const fhir_url = document.getElementById('fhir_url').value;
  const auth_url = document.getElementById('auth_url').value;
  const myHeaders = new Headers();
  myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
  const urlencoded = new URLSearchParams();
  urlencoded.append("client_id", "person-portal");
  urlencoded.append("username", username);
  urlencoded.append("password", password);
  urlencoded.append("grant_type", "password");
  urlencoded.append("scope", "offline_access openid");
  const requestOptions = {
  method: "POST",
  headers: myHeaders,
  body: urlencoded,
  redirect: "follow"
  };
  fetch(auth_url + "/protocol/openid-connect/token", requestOptions)
  .then((response) => response.json())
  .then((result) => {
  sessionStorage.setItem('SMART_TOKEN', JSON.stringify(result));
  sessionStorage.setItem('AUTH_URL', auth_url);
  sessionStorage.setItem('FHIR_URL', fhir_url);
  window.location.href = 'home';
  })
  .catch((error) => {
  console.error(error);
  document.getElementById('info').textContent = 'An error occurred. Please try
  again.';
  });
  });
  </script>
  
  

  1. Creating home.html This page will be the home page after the user logs in. It will display the profile of authorized user.
Code Snippet

  
  <div class="body-card">
  <h1> Mini Apps</h1>
  </div>
  <div class="body-card">
  This is the home page of the mini apps. They are discovered and activated by super
  app users and once
  used they can also be easily removed from the UI. In general, mini apps are
  developed to complete one or
  more specific tasks of a larger app, such as the functionality to contract services, buy
  a product, make
  donations, and rent something, among others.
  </div>
  <div class="body-card">
  <div class="user-card">
  <h2>User Information</h2>
  <div class="user-info">
  <label>Subject (sub):</label>
  <span id="sub"></span>
  </div>
  <div class="user-info">
  <label>Email Verified:</label>
  <span id="email_verified"></span>
  </div>
  <div class="user-info">
  <label>Phone Number:</label>
  <span id="phoneNumber"></span>
  </div>
  <div class="user-info">
  <label>Name:</label>
  <span id="name"></span>
  </div>
  <div class="user-info">
  <label>Preferred Username:</label>
  <span id="preferred_username"></span>
  </div>
  <div class="user-info">
  <label>Given Name:</label>
  <span id="given_name"></span>
  </div>
  <div class="user-info">
  <label>ID Number:</label>
  <span id="idNo"></span>
  </div>
  <div class="user-info">
  <label>Family Name:</label>
  <span id="family_name"></span>
  </div>
  <div class="user-info">
  <label>Email:</label>
  <span id="email"></span>
  </div>
  </div>
  </div>
  </main>
  <footer>
  <p>&copy; 2024 My Website. All rights reserved.</p>
  </footer>
  
  
Code Snippet

  
// do checkin session storage if smart token is exist
if (sessionStorage.getItem("SMART_TOKEN") == null) {
//if the smart token not exist redirect to login
window.location.href = 'login';
} else {
//if the smart token is exist do a process to get userinfo
var AUTH_URL = sessionStorage.getItem("AUTH_URL");
var FHIR_URL = sessionStorage.getItem("FHIR_URL");
var SMART_TOKEN = sessionStorage.getItem("SMART_TOKEN");
var token = JSON.parse(SMART_TOKEN);
const myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
myHeaders.append("Authorization", "bearer " + token.access_token);
const requestOptions = {
method: "GET",
headers: myHeaders,
};
var patientId = null;
fetch(AUTH_URL + "/protocol/openid-connect/userinfo", requestOptions)
.then((response) => response.json())
.then((result) => {
console.log(result);
document.getElementById('sub').textContent = result.sub;
document.getElementById('email_verified').textContent = result.email_verified;
document.getElementById('phoneNumber').textContent = result.phoneNumber;
document.getElementById('name').textContent = result.name;
document.getElementById('preferred_username').textContent =
result.preferred_username;
document.getElementById('given_name').textContent = result.given_name;
document.getElementById('idNo').textContent = result.idNo;
document.getElementById('family_name').textContent = result.family_name;
document.getElementById('email').textContent = result.email;
document.getElementById('patient').textContent = result.patient;
document.getElementById('fhir_url').textContent = FHIR_URL;
const myHeaders2 = new Headers();
myHeaders2.append("Authorization", "bearer " + token.access_token);
const requestOptions2 = {
method: "GET",
headers: myHeaders2,
};
fetch(FHIR_URL + "/Patient/" + result.patient, requestOptions2)
.then((response) => response.json())
.then((result) => {
console.log(result);
document.getElementById('patient_id').textContent = result.id;
document.getElementById('patient_resource').textContent = result.resourceType;
document.getElementById('patient_source').textContent = result.meta.source;
document.getElementById('patient_identifier').textContent = result.identifier[0].value;
document.getElementById('patient_name').textContent = result.name[0].text;
document.getElementById('patient_gender').textContent = result.gender;
document.getElementById('patient_birthdate').textContent = result.birthDate;
for (var i = 0; i < result.telecom.length; i++) {
if (result.telecom[i].system == "phone") {
document.getElementById('patient_phone').textContent = result.telecom[i].value;
}
if (result.telecom[i].system == "email") {
document.getElementById('patient_email').textContent = result.telecom[i].value;
}
}
for (var i = 0; i < result.address.length; i++) {
document.getElementById('patient_address').textContent = result.address[i].line[0] +
result.address[i].postalCode + " " + result.address[i].city;
}
})
.catch((error) => {
console.error(error);
document.getElementById('info').textContent = 'An error occurred. Please try again.';
});
})
.catch((error) => {
console.error(error);
document.getElementById('info').textContent = 'An error occurred. Please try again.';
});
}
  
  

  1. Creating index.html page This page will contain initiate page. In this section. The page will do a checking on session storage to validate the SMART_TOKEN.
  • hightlight : sessionStorage.getItem("SMART_TOKEN")
Code Snippet

  
  <form id="loginForm">
  <h2>Login</h2>
  <hr>
  </hr>
  <label for="username">Username:</label>
  <input type="text" id="username" name="username" required />
  <br />
  <label for="password">Password:</label>
  <input type="password" id="password" name="password" required />
  <br />
  <button type="submit">Login</button>
  </form>
  <script type="text/javascript">
  document.getElementById('loginForm').addEventListener('submit', function (event)
  {
  event.preventDefault(); // Prevent the form from submitting the traditional way
  const username = document.getElementById('username').value;
  const password = document.getElementById('password').value;
  const fhir_url = document.getElementById('fhir_url').value;
  const auth_url = document.getElementById('auth_url').value;
  const myHeaders = new Headers();
  myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
  const urlencoded = new URLSearchParams();
  urlencoded.append("client_id", "person-portal");
  urlencoded.append("username", username);
  urlencoded.append("password", password);
  urlencoded.append("grant_type", "password");
  urlencoded.append("scope", "offline_access openid");
  const requestOptions = {
  method: "POST",
  headers: myHeaders,
  body: urlencoded,
  redirect: "follow"
  };
  fetch(auth_url + "/protocol/openid-connect/token", requestOptions)
  .then((response) => response.json())
  .then((result) => {
  sessionStorage.setItem('SMART_TOKEN', JSON.stringify(result));
  sessionStorage.setItem('AUTH_URL', auth_url);
  sessionStorage.setItem('FHIR_URL', fhir_url);
  window.location.href = 'home';
  })
  .catch((error) => {
  console.error(error);
  document.getElementById('info').textContent = 'An error occurred. Please try
  again.';
  });
  });
  </script>
  
  


Run and Test App

Now that the Mini App is created and Authorization is configured, we need to make sure that everything is functioning correctly.

  1. Open the “terminal/command” prompt.
  2. Navigate to the “project directory,” then run the following command:
  3. cd

Note: replace the with the actual path to project directory. i.e. D://mini-app

a. Run the following command: npm install Note: this will install required dependencies for a node project listed in the package.json file. (You need to run this command only once unless you make any changes in the package.json file.)

b. Run the command to start the server: npm start

c. Copy and paste the following URL into the address bar:

http://localhost:9200

After launching, an authentication page similar to the image below will appear:

figure-4

Enter the credentials then select “Login,” (Use the credential of the user created in the previous section.) The authorization screen should appear like the image below: Username: haziq@mhnexus.com Password: P@ssw0rd

figure-5

Congrats, you’ve now successfully created and tested your first mini app. SMART on FHIR is a data standard that enables applications to access information in electronic health record (EHR) systems. An application developer can write a single application that connects to any EHR system that has adopted the standard.