Introduction
What is SMART on FHIR?โ
SMART on FHIR (Substitutable Medical Applications, Reusable Technologies) is an open standard that defines how healthcare apps connect to Electronic Health Record systems. It layers OAuth 2.0 and OpenID Connect on top of HL7 FHIR R4 to answer three questions:
- Which EHR is the app talking to? โ resolved via the
issparameter and dynamic discovery of/.well-known/smart-configuration - Who is the patient and clinician in context? โ carried in the
launchtoken and returned as extras in the OAuth2 token response - What data can the app access? โ governed by SMART scopes (
patient/Patient.rs,patient/Condition.rs, etc.) granted during the OAuth2 flow
The result is a single app that can launch inside any SMART-compliant EHR โ Epic, Cerner, and others โ without being hard-coded to any one vendor's proprietary API.
What this client providesโ
This project is a production-ready SMART on FHIR EHR launch client targeting Epic, built on Spring Boot 3 and Java 21. It implements the complete launch handshake and exposes the retrieved FHIR data through a Thymeleaf UI and a REST API.
Epic EHR โโlaunchโโโถ Your App โโFHIR APIโโโถ Epic FHIR R4
SMART HAPI client
handshake + bearer token
What is handled automaticallyโ
Once the SMART handshake completes, the app gives you:
SmartLaunchContextโ a typed session object holding the access token, patient ID, encounter ID,needPatientBannerflag, granted scopes, token expiry, and OIDC user profileFhirClientFactoryโ a HAPI R4IGenericClientpre-configured with a bearer token interceptor, pointed at the correct FHIR server for this hospitalTokenRefreshFilterโ transparent token refresh 120 seconds before expiry on every/api/**request โ clinicians never see an unexpected 401SecurityConfigโ Spring Security 6 filter chain with session fixation protection, CSRF (Double-Submit Cookie), anddenyAll()fallback for unknown routes- A working UI โ patient banner, dashboard, conditions table, medications table, clinician profile from OIDC
What you build on topโ
The app is a functional starting point. You extend it by:
- Adding new FHIR resource endpoints in
PatientDataController - Adding new UI pages in
UiControllerandtemplates/ - Requesting additional scopes in
application.yml - Connecting to your own backend services or databases
SMART App Launch v2.2โ
This client implements SMART App Launch 2.2, the current specification. Key differences from v1 (which most older libraries including HealthLX implement):
| Capability | SMART v1 | SMART v2 (this client) |
|---|---|---|
| Server discovery | Static YAML config | Dynamic /.well-known/smart-configuration |
| PKCE | Optional | Required (S256 enforced) |
| Scope syntax | patient/*.read | patient/Patient.rs |
aud parameter | Not required | Required by Epic |
| Standalone launch | Partial | Full launch/patient support |
EHR launch vs standalone launchโ
The app supports both SMART launch modes:
EHR launchโ
A clinician clicks your app's button inside Epic Hyperspace. Epic sends:
GET /launch?iss=https://hospital.epic.com/.../FHIR/R4&launch=abc123opaque
The launch token pre-selects the patient and encounter. After the OAuth2 handshake,
SmartLaunchContext.patientId() is always populated.
Standalone launchโ
A user navigates directly to your app's URL (bookmarked, from a patient portal, etc.).
Only iss is provided โ no launch token. The OAuth2 flow uses launch/patient scope,
which may trigger a patient picker in the auth server.
SmartLaunchController detects the mode automatically by checking whether the launch
query parameter is present.
Technology stackโ
| Layer | Technology | Version |
|---|---|---|
| Runtime | Java | 21 |
| Framework | Spring Boot | 3.3.5 |
| Security | Spring Security | 6.x |
| FHIR client | HAPI FHIR | 7.4.5 |
| FHIR version | HL7 FHIR | R4 |
| Templating | Thymeleaf | 3.x |
| Build | Maven | 3.9+ |
| Testing | JUnit 5 + WireMock | 5.x / 3.6.0 |
Project structureโ
smart-fhir-client/
โโโ src/main/java/com/smartfhir/client/
โ โโโ auth/ PKCE generation + authorize URL builder
โ โโโ context/ SmartLaunchContext + extraction from token response
โ โโโ discovery/ /.well-known/smart-configuration fetching + caching
โ โโโ fhir/ HAPI FHIR client factory + data controller
โ โโโ launch/ /launch endpoint โ EHR and standalone modes
โ โโโ oidc/ id_token validation + UserProfile extraction
โ โโโ refresh/ Proactive token refresh filter + service
โ โโโ security/ Spring Security 6 filter chain + SMART session bridge
โ โโโ token/ /callback endpoint + token exchange service