ng-smart-on-fhir
Version:
[](https://srdc.com.tr/en)
408 lines (318 loc) • 16.4 kB
Markdown
[](https://srdc.com.tr/en)
# NgSmartOnFhir - 🔥HL7 SMART-on-FHIR Library for Angular
[](https://v17.angular.io/docs)
[](https://www.npmjs.com/package/ng-smart-on-fhir)
[](https://hl7.org/fhir/)
An Angular library to provide SMART-on-FHIR authorization with:
- Login, Callback, Launch pages
- Routing wrapper
- Routing Guard
- SMART-on-FHIR authentication service
- Authenticated FHIR client service
- SMART Health Card QR reader and parser components
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.3.0.
## Build
Run `ng build ng-smart-on-fhir` to build the project. The build artifacts will be stored in the `dist/` directory.
## Installation
### 1. Library and FHIR typings
```
npm install /fhir --save-dev
npm install ng-smart-on-fhir --save
```
### 2. Bootstrap (Optional)
The `ng-smart-on-fhir` library has visual components such as the Login page.
If you prefer to use the library's predefined bootstrap theme, you need to install
Bootstrap as well.
```
npm install bootstrap --save
```
## Usage
### 1. Importing the Module
Import the `SmartOnFhirModule` to your app module with the necessary [configurations](smartonfhirconfig).
***app.module.ts***
```{ts}
import { SmartOnFhirModule } from '/smart-on-fhir';
({
declarations: [
AppComponent
],
imports: [
BrowserModule,
SmartOnFhirModule.forRoot(environment.smartConfig) // import module with configurations
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
```
***environment.ts***
```{ts}
export const environment = {
smartConfig: {
clientIds: { // Client IDs to be used in Launch flow
'https://lforms-smart-fhir.nlm.nih.gov/v/r4/fhir': 'srdc-qrisk'
},
redirectUrl: appBaseUrl + '/callback',
loginClients: [ // buttons for initiating SMART Login flow
{
label: 'EPIC',
image: 'asset/epic.png', // image to be displayed in login page
// if image is not provided, a button with the label will be shown
// you can set background, color, etc. to customize the button
iss: 'https://fhir.epic.com/interconnect-fhir-oauth/api/FHIR/R4/',
redirectUri: appBaseUrl + '/callback',
clientId: '<epic-client-id>',
scope: 'launch launch/patient patient/*.*'
}
],
launchClients: [ // links to the providers with SMART Launch flow
{
label: 'NIH - Smart Launch',
background: '#326295',
color: 'white',
url: 'https://lforms-smart-fhir.nlm.nih.gov/'
}
]
}
}
```
Configuration model is described below:
#### SmartOnFhirConfig
| Field | Optional | Type | Description |
|-------------------------------|-------------|--------------------------------------------------|--------------------------------------------------------------------------------------------------------------|
| logo | true | string | Logo image url to be used in Login page |
| title | true | string | Title string to be used in Login page |
| shcLoginEnabled<sup>[1]</sup> | true | boolean | Enable login with Smart Health Cards (SHC) |
| shcCallbackUrl<sup>[1]</sup> | true | string | Callback url to handle SHC Logins |
| clientIds<sup>[2]</sup> | conditional | object | { Issuer -> clientId } mappings for launch clients |
| clientId<sup>[2]</sup> | conditional | string | Client ID if there is single client ID for any client or to use when the issuer is not matched during launch |
| redirectUrl<sup>[2]</sup> | conditional | string | Redirect Url for Launch clients |
| launchClients<sup>[2]</sup> | true | Array<[LaunchClientConfig](#launchclientconfig)> | List of clients using SMART App Launch flow |
| loginClients<sup>[3]</sup> | true | Array<[LoginClientConfig](#loginclientconfig)> | List of clients using the SMART Login flow |
*[1] The "SMART Health Cards" is a standard developed by HL7 and piloted during the COVID pandemic to allow citizens share their vaccination data as QR codes with trusted
authorities. [Learn More]()*
*[2] The SMART App Launch flow allows integration between FHIR based EHR systems and other applications by defining a standard to grant permissions to an application directly from the EHR's launcher application. [Learn More]()*
*[3] The SMART Login flow is an authentication mechanism based on OAuth2 with the addition of SMART scopes that indicates the access rights for a patient's data in the EHR. [Learn More]()*
#### LaunchClientConfig
| Field | Optional | Type | Description |
|-----------------------------|----------|--------|-----------------------------------------|
| label | false | string | Label of the launcher EHR |
| url | false | string | URL of the EHR that contains the launch |
| image | true | string | Image of the EHR logo<sup>*</sup> |
| icon | true | string | Icon class for the button |
| background | true | string | Background color of the button |
| color | true | string | Text color of the button |
**If the `image` is provided, it will be shown in the login page. Otherwise, it will appear as a button with `label` as text.*
#### LoginClientConfig
export interface LoginClientConfig {
promptLogin?: boolean;
logoutUri?: string;
isPublic?: boolean;
}
| Field | Optional | Type | Description |
|-------------|----------|---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
| label | false | string | Label of the launcher EHR |
| image | true | string | Image of the EHR logo<sup>*</sup> |
| icon | true | string | Icon class for the button |
| background | true | string | Background color of the button |
| color | true | string | Text color of the button |
| clientId | false | string | Client ID of the application in the login provider |
| iss | false | string | Issuer (login provider) |
| redirectUri | false | string | Callback page after login to handle token |
| scope | false | string | Requested scopes (add `launch/patient` scope for the patient facing apps) |
| aud | true | string | Use if the `aud` claim should be different than the `iss` |
| promptLogin | true | boolean | If set to true, the prompt=login parameter is added to the authentication request so the user will be asked for credentials even if an active session exists |
| logoutUri | true | string | Logout url of the authentication provider to securely terminate the user session |
| isPublic | true | boolean | If set to true, the authentication will be disabled. Additionally, if `launch/patient` scope exists, a patient selection page will be shown. |
**If the `image` is provided, it will be shown in the login page. Otherwise, it will appear as a button with `label` as text.*
### 2. Adding SMART Routes (Login, Callback, Launch) to Your Application
Adding SMART authentication handling routes in your **Routing Module**:
```
import { NgModule } from '/core';
import { RouterModule, Routes } from '/router';
import {withSmartHandlerRoutes} from "smart-on-fhir";
import {HomeComponent} from "./home/home.component";
import {ResultsComponent} from "./results/results.component";
const routes: Routes = withSmartHandlerRoutes( // wrap your own routes with the SMART routes
[
{
path: '',
component: HomeComponent
}
], // your app routes
'/', // base url to be redirected
'both', // supported login methods; options are: 'launch'|'client'|'both'
true // redirect to login page if not authorized
);
({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
```
> The `withSmartHandlerRoutes` method adds an auth Guard to your routes automatically if `redirectToLoginIfUnauthorized` parameter is `true`.
### 3. Inject the SMART Fhir Client Service in Your Components
```
...
import {SmartOnFhirService} from "@srdc/smart-on-fhir"
({
selector: 'app-component',
templateUrl: './app.component.html',
styleUrl: './app.component.scss'
})
export class AppComponent {
private client: Client|undefined;
patient: fhir4.Patient|undefined;
vitalSigns: fhir4.Bundle<fhir4.Observation>|undefined;
constructor(private smartOnFhirService: SmartOnFhirService) {}
async ngOnInit() {
this.patient = await this.sof.getPatient();
this.vitalSigns = await this.sof.search<fhir4.Observation>(
"Observation",
{ category: 'vital-signs' }
);
}
...
```
### 4. Theming
The NgSmartOnFhir library provides two predefined themes:
- Default
- Bootstrap
#### Default Theme
You can import the default theme to your root `style.scss` file, or to the project styles in `angular.json`.
```{sass}
'node_modules/ng-smart-on-fhir/themes/default.scss'
```
You can also override the classes to design a custom theme:
```
'node_modules/ng-smart-on-fhir/themes/default.scss'
.sof-shadow { box-shadow: 0 0 2px 0 #ccc; }
.sof-light-background { background: #e0e0e0 !important; }
.sof-primary-background { background: #16A4D8 !important; }
.sof-text-light { color: #ffffff !important; }
.sof-text-gray { color: #999999 !important; }
.sof-text-dark { color: #000000 !important; }
.sof-text-danger { color: #ba1239 !important; }
.sof-text-center { text-align: center; }
.sof-text-bold { font-weight: bold; }
.sof-card { box-shadow: 0 0 3px 0 #eee; }
.sof-card-header {
background: #1181aa;
color: white;
}
.sof-login-card-header { /* ... */ }
.sof-button {
background: #ffffff;
color: #000000;
&:hover {
background: #e0e0e0;
}
}
/* .sof-button-[primary, secondary, ...] { ... } */
.sof-alert-danger {
background: #ff979b;
color: #550509;
}
.sof-login-client-w-image { /* ... */ }
/* ... */
```
You can find the custom classes in the [default.scss](https://github.com/srdc/ng-smart-on-fhir/blob/main/src/lib/themes/default.scss) file.
#### Bootstrap Theme
You can import bootstrap css to your project in `angular.json`:
```
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
...
"architect": {
"build": {
...
"styles": [
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"src/styles.css"
],
"scripts": []
},
...
"test": {
...
"styles": [
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"src/styles.css"
],
"scripts": []
}
}
}
}
}
}
```
Or you can import it to your `styles.scss` and customize theme variables:
```
/* You can add global styles to this file, and also import other style files */
"../../../node_modules/bootstrap/scss/functions";
$_primary: #761eb1;
$_secondary: #9328DA;
$theme-colors: (
"light": #f5f5f5,
"dark": adjust-hue(shade-color($_primary, 45), 10),
"primary": $_primary,
"secondary": $_secondary,
"info": #abedf6,
"success": #b8e186,
"warning": #fde47f,
"danger": #f32509,
"primary-text": #f8f9fa,
"secondary-text": #f8f9fa
);
.btn {
color: #f8f9fa !important;
}
.input-group > input:focus + .input-group-text {
background: $_primary !important;
}
"../../../node_modules/bootstrap/scss/variables";
"../../../node_modules/bootstrap/scss/variables-dark";
"../../../node_modules/bootstrap/scss/maps";
"../../../node_modules/bootstrap/scss/mixins";
"../../../node_modules/bootstrap/scss/root";
"../../../node_modules/bootstrap/scss/buttons";
"../../../node_modules/bootstrap/scss/bootstrap";
```
After importing bootstrap, add the bootstrap theme to your root `styles.scss` file or `angular.json`:
```
/* ...import/customize bootsrap */
'../../../node_modules/ng-smart-on-fhir/themes/bootstrap.scss';
```
## Development
You can continue development of this library by including it as a `devDependency` in your `package.json`. Before doing it, you will need to link the library.
First, build the library:
```
cd path/to/smart-on-fhir
ng build smart-on-fhir
```
Then, link the `smart-on-fhir` library globally:
```
cd path/to/smart-on-fhir/dist/smart-on-fhir
npm link
```
Next, link the `smart-on-fhir` library to your project:
```
cd path/to/your-project
npm link smart-on-fhir
```
Finally, add your `smart-on-fhir` library as a `devDependency` in your `package.json`:
```
"devDependencies": {
"smart-on-fhir": "file:.path/to/smart-on-fhir/dist/smart-on-fhir",
}
```
Import the module in your project with something like this:
```
import {
SmartOnFhirModule
} from "../../../../../../smart-on-fhir/projects/smart-on-fhir/src/lib/smart-on-fhir.module";
```