Quick Start
Two paths depending on whether you have an Epic developer account:
| SMART Health IT sandbox | Epic non-production sandbox | |
|---|---|---|
| Account needed | None | Free — fhir.epic.com |
| Real Epic data | No — synthetic Synthea patients | Yes — 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.
Option A — SMART Health IT sandbox (recommended first step)
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
- Open launch.smarthealthit.org in your browser
- Set App Launch URL to
http://localhost:8080/launch - Set FHIR Version to
R4 - Choose Launch Type →
Provider EHR Launch - Select any patient from the list
- Click Launch
Your browser redirects through the SMART handshake and lands on the dashboard at
http://localhost:8080/.
- 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
openidscope 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
- Open open.epic.com/launchpad
- Select SMART on FHIR App Launch
- Set Launch URL to
http://localhost:8080/launch - Pick a test patient (e.g.
Camila Lopez) - 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 line | Class | Package |
|---|---|---|
EHR launch received | SmartLaunchController | launch/ |
Fetching SMART configuration | SmartDiscoveryService | discovery/ |
PKCE generated | SmartAuthRequestBuilder | auth/ |
Redirecting to authorize | SmartLaunchController | launch/ |
SMART EHR launch complete | SmartCallbackController | token/ |
id_token validated | IdTokenValidator | oidc/ |
Fetching Patient/ | UiController | ui/ |
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
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.
You haven't completed a launch yet — the session has no SmartLaunchContext.
Run a launch from LaunchPad or SMART Health IT first.
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.
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.
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
- Configuration reference → — understand every property
- Epic Registration → — set up your free Epic developer account
- Architecture Overview → — understand the codebase structure
- EHR Launch Flow → — deep dive into the launch sequence