Skip to main content

Quick Start

Two paths depending on whether you have an Epic developer account:

SMART Health IT sandboxEpic non-production sandbox
Account neededNoneFree — fhir.epic.com
Real Epic dataNo — synthetic Synthea patientsYes — Epic's own sandbox patients
Time to first launch~5 minutes~75 minutes (includes 1-hour sync)
Maven profile-Psmart-Pepic

Start with the SMART Health IT sandbox — it requires nothing and proves the full flow works.


1. Clone the repository

git clone https://github.com/your-org/smart-fhir-client.git
cd smart-fhir-client

2. Start the app

mvn spring-boot:run -Dspring-boot.run.profiles=smart

You should see:

INFO  SmartFhirApplication - Started SmartFhirApplication in 4.2 seconds
INFO FhirClientFactory - FhirClientFactory ready — socketTimeout=30000ms, connectTimeout=10000ms

3. Verify the health endpoint

curl http://localhost:8080/health
{"status":"UP","app":"smart-fhir-client","epicClientId":"growth_ch..."}

4. Launch from SMART Health IT

  1. Open launch.smarthealthit.org in your browser
  2. Set App Launch URL to http://localhost:8080/launch
  3. Set FHIR Version to R4
  4. Choose Launch TypeProvider EHR Launch
  5. Select any patient from the list
  6. Click Launch

Your browser redirects through the SMART handshake and lands on the dashboard at http://localhost:8080/.

What you should see
  • Blue patient banner with the selected patient's name
  • Dashboard with stat cards showing condition and medication counts
  • Navigation links to Patient, Conditions, Medications pages
  • Clinician profile card (if openid scope was granted)

Option B — Epic non-production sandbox

1. Register with Epic and get a client ID

Follow the Epic Registration guide →. This takes about 15 minutes plus a 1-hour sync wait.

2. Export your client ID

export EPIC_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

3. Start the app with the Epic profile

mvn spring-boot:run -Dspring-boot.run.profiles=epic

4. Launch from Epic LaunchPad

  1. Open open.epic.com/launchpad
  2. Select SMART on FHIR App Launch
  3. Set Launch URL to http://localhost:8080/launch
  4. Pick a test patient (e.g. Camila Lopez)
  5. Click Launch

What happens during a launch

Here is what the logs show for a successful EHR launch:

INFO  SmartLaunchController  - EHR launch received — iss=https://launch.smarthealthit.org/v/r4/fhir
INFO SmartDiscoveryService - Fetching SMART configuration from ISS: https://...
INFO SmartDiscoveryService - SMART configuration cached — authEndpoint=..., tokenEndpoint=...
DEBUG SmartAuthRequestBuilder - PKCE generated and stored in session — challenge method: S256
INFO SmartLaunchController - Redirecting to authorize endpoint — mode=ehr, state=abc123...
INFO SmartCallbackController - SMART EHR launch complete — patient=eXXXX, encounter=eYYYY, scope=...
INFO IdTokenValidator - id_token validated — subject=eProvider123
INFO UiController - Fetching Patient/eXXXX

Each log line maps to a class and package in the codebase:

Log lineClassPackage
EHR launch receivedSmartLaunchControllerlaunch/
Fetching SMART configurationSmartDiscoveryServicediscovery/
PKCE generatedSmartAuthRequestBuilderauth/
Redirecting to authorizeSmartLaunchControllerlaunch/
SMART EHR launch completeSmartCallbackControllertoken/
id_token validatedIdTokenValidatoroidc/
Fetching Patient/UiControllerui/

Exploring the API

After a successful launch, the session is authenticated. Use curl or your browser to explore all API endpoints:

Session info

Always safe — works before patient is selected (standalone launch).

    curl http://localhost:8080/api/session
    {
"launchMode": "ehr",
"patientId": "erXuFYUfucBZaryVksYEcMg3",
"encounterId": "eEnc-789",
"needPatientBanner": true,
"grantedScopes": "launch openid fhirUser patient/Patient.rs ...",
"hasUserProfile": true,
"tokenExpiresAt": "2025-01-15T10:30:00Z"
}

Clinician profile

Requires openid scope.

    curl http://localhost:8080/api/me
    {
"subject": "eProvider-ABC123",
"displayName": "Dr. Jane Smith",
"fhirUser": "Practitioner/eProvider-ABC123",
"issuer": "https://fhir.epic.com/..."
}

Patient

Requires patient/Patient.rs scope.

    curl http://localhost:8080/api/patient
    {
"id": "erXuFYUfucBZaryVksYEcMg3",
"name": "Camila Lopez",
"birthDate": "1985-03-12",
"gender": "female",
"patientBanner": true
}

Conditions

Requires patient/Condition.rs scope.

    curl http://localhost:8080/api/conditions
    [
\{
"id": "eCond-001",
"code": "44054006",
"display": "Type 2 diabetes mellitus",
"status": "active"
\}
]

Summary

Combines all available data in one call.

    curl http://localhost:8080/api/summary

Running the tests

Unit tests only (fast, no network)

mvn test

Runs 140+ unit tests with WireMock stubs — no internet access required. Typically completes in 15–30 seconds.

SMART Health IT integration tests

mvn verify -Psmart

Runs SmartHealthSandboxIT — fetches the real discovery document from launch.smarthealthit.org and reads a known synthetic patient. Requires internet access.

Epic sandbox integration tests

export EPIC_CLIENT_ID=your-non-production-client-id
mvn verify -Pepic

Runs EpicSandboxIT — validates Epic's discovery document, builds an authorize URL with all Epic-required parameters, and reads a known Epic sandbox patient.


Common issues

Port 8080 is already in use

Change the port in application.yml:

server:
port: 8081

Update your redirect URI accordingly and re-register it in your Epic app if using the Epic profile.

The app starts but the session endpoint returns 401

You haven't completed a launch yet — the session has no SmartLaunchContext. Run a launch from LaunchPad or SMART Health IT first.

Launch redirects to an error page in the browser

Check the app logs. The most common cause is a mismatched redirect URI — what you registered in Epic or SMART Health IT must exactly match smart.epic.redirect-uri in application.yml.

Conditions or medications return an empty array

The selected patient may not have active conditions or medications in the sandbox. Try a different patient, or check that the relevant scopes are in application.yml.

id_token validation warning in the logs
WARN  IdTokenValidator - JWKS fetch failed — skipping signature check

This is non-fatal. FHIR data access works normally. Full cryptographic RS256 signature verification requires adding nimbus-jose-jwt — see the OIDC guide.


Next steps