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 Type → Provider 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​