Nirmitee.io
Epic Integration · SMART on FHIR

Build a SMART on FHIR App for Epic.

The three launch types, the OAuth 2.0 flow, the scopes, and the app registration that actually gets you live in Epic — explained by engineers who ship SMART apps, on patterns validated against Inferno g10.

EHR launchStandaloneBackendOAuth 2.0US CoreSMART App Launch v2 · Inferno g10-validated
3
launch types: provider EHR-launch, patient standalone, backend
v2
SMART App Launch — granular c/r/u/d/s scopes
R4
FHIR R4 / US Core resources & endpoints
47/47
Inferno g10 conformance tests passing
What Is SMART on FHIR?

The Standard Way Apps Run on Epic

SMART on FHIR is the HL7 standard that lets a third-party app authenticate to an EHR with OAuth 2.0 and read or write data through FHIR APIs. It's how virtually every modern app connects to Epic — and Epic officially recommends and supports it. Instead of proprietary hooks, you get a portable pattern that also works across Oracle Health, athenahealth, and the rest.

The single most important decision is your launch type — it determines how your app starts, who authorizes it, which scopes you request, and how Epic registers you. There are three: provider (EHR launch), patient (standalone), and backend (system-to-system). Pick the wrong one and you rebuild; pick the right one and the rest of the integration follows. Below, we break down all three the way we'd scope them with you.

Interactive · The Three Launch Types

Which SMART Launch Does Your App Need?

Provider, patient, or backend — each has a different flow, scope pattern, and Epic registration. Pick one.

Provider · EHR Launch

Your app opens inside Epic (in the clinician's Hyperdrive session) from a button or activity in the chart. Epic hands your app a launch token plus the current patient, encounter, and user context.

How It Starts

Epic opens your registered launch URL with launch and iss (the FHIR base URL). Your app then runs the standard OAuth /authorize/token exchange, passing the launch parameter back.

Typical Scopes

launch, openid, fhirUser, patient/Patient.r, patient/Observation.rs, user/*.rs — scoped to the launched patient/user.

Epic Registration

Register as a Clinician-facing app with an EHR-launch redirect URI. It surfaces in the provider's workflow and runs in Hyperdrive (no COM dependencies).

Watch For

Context is the launched patient only — no patient picker. Token lifetimes are short; you refresh within the session, not across days.

Best for

Clinical decision support, documentation, ordering, and any tool that lives in the clinician's workflow at the point of care.

Patient · Standalone Launch

The patient starts your app from outside Epic (your website or mobile app) and authorizes it against MyChart. There's no launch token — the patient logs in and consents to the scopes you request.

How It Starts

Your app sends the patient to Epic's /authorize endpoint. The patient authenticates via MyChart and approves your scopes; you exchange the code for a token at /token.

Typical Scopes

openid, fhirUser, offline_access (for a refresh token), patient/*.rs — access to that patient's own record.

Epic Registration

Register as a Patient-facing app. MyChart is the authorization server; use offline_access so you can refresh without re-prompting the patient.

Watch For

You only ever get the authorizing patient's data. Handle refresh tokens securely, and expect each health system's MyChart to be a separate connection.

Best for

Personal health records, patient engagement, remote monitoring apps, and patient-mediated data products.

Backend · System-to-System

No human in the loop. Your server authenticates directly to Epic with the SMART Backend Services flow — a signed JWT using your private key (you upload the public key to Epic). Used for automated data movement and bulk export.

How It Starts

Your server creates and signs a JWT, then calls /token with grant_type=client_credentials and a client_assertion. You get a system-scoped access token — no user, no launch.

Typical Scopes

system/Observation.rs, system/*.rs — plus FHIR Bulk Data $export for population-scale pulls.

Epic Registration

Upload production and non-production public keys (or a JWK Set URL); public keys must be a base64-encoded X.509 certificate. Epic recommends backend for IPS queries and $match.

Watch For

Key management is the whole game — rotate carefully, keep prod/non-prod separate, and remember the app record is immutable once ready for production.

Best for

Data pipelines, analytics, population health, and any automated server-to-server flow with no interactive user.

The OAuth 2.0 Flow

From Launch to a FHIR Call, Step by Step

Provider and patient apps share the same authorization-code flow; backend swaps it for a signed-JWT client-credentials grant. Here's the request that starts it.

  authorization request — SMART EHR launch
# 1. Provider EHR launch — redirect the browser to Epic's authorize endpointGET https://{fhir-base}/oauth2/authorize?response_type=code&client_id={your-non-prod-client-id}&redirect_uri=https://yourapp.com/callback&scope=launch openid fhirUser patient/Observation.rs&launch={launch-token-from-epic}&state={csrf}&aud={fhir-base}# 2. Epic redirects back with ?code=... → exchange it at the token endpointPOST https://{fhir-base}/oauth2/tokengrant_type=authorization_code & code=... & redirect_uri=...# 3. Response carries the token AND the launch context{ "access_token": "...", "patient": "e0w0...","encounter": "eXy...", "scope": "patient/Observation.rs" }# 4. Call FHIR with the bearer tokenGET https://{fhir-base}/api/FHIR/R4/Observation?patient=e0w0...Authorization: Bearer {access_token}

Illustrative — endpoints, parameters, and context follow the SMART App Launch v2 spec that Epic implements. Backend apps skip steps 1–2 and POST a signed JWT assertion to /token instead.

SMART v2 Scopes

Ask for Exactly What You Need — Nothing More

SMART App Launch v2 replaced v1's blunt .read/.write with granular per-operation permissions. A scope is context / resource . operations.

Scope
What it grants
Context prefix
patient/Observation.rs
Read & search Observations for the launched patient only.
patient/ — one patient
user/*.rs
Read & search any resource the logged-in user is allowed to see.
user/ — a user's access
system/Observation.rus
Read, update & search Observations with no user (backend).
system/ — no user
launch · openid · fhirUser
EHR launch context, OpenID Connect identity, and the FHIR resource for the user.
identity / launch
offline_access
Issues a refresh token so patient apps keep access without re-prompting.
patient apps

The operation letters are create · read · update · delete · search. v1 → v2 maps .read → .rs, .write → .cud, .* → .cruds. Least-privilege scoping speeds up every customer's security review.

Registering Your App with Epic

From fhir.epic.com to a Live Launch

SMART is the easy part; the Epic registration mechanics are where teams stumble. Four things to get right.

1

Register & Get Client IDs

Create the app on fhir.epic.com; you receive both a non-production and a production client ID.

2

Set Launch Type & Redirect

Declare clinician-, patient-, or backend-facing; add redirect URIs; for backend, upload your X.509 public key.

3

Test in the Sandbox

Use the non-prod ID against Epic's "Try It" test patients; validate scopes and launch context.

4

Mark Ready for Production

Required before any customer can use it — and it locks the app record. Changes need a new registration.

Because the record is immutable once live, we lock down your scopes, redirect URIs, and launch type before you mark it ready — so you're not re-registering later. See the full Epic vendor journey.

Common Pitfalls

Where SMART-on-Epic Builds Go Wrong

The mistakes we're most often called in to fix.

Picking the wrong launch type

Building a provider app when you needed patient (or vice-versa) means re-registering and re-scoping. Decide launch type first.

Over-broad scopes

Requesting *.cruds when you only read slows down every customer's security review. Ask for least privilege.

Editing a locked app record

Once marked ready for production the record is immutable — changing a redirect URI means a whole new app. Get it right up front.

Forgetting refresh tokens

Patient apps that skip offline_access force patients to re-authorize constantly. Backend apps must handle JWT re-signing.

FAQ

SMART on FHIR for Epic, Answered

The questions we hear most when teams start a SMART build.

What's the Difference Between EHR Launch and Standalone Launch?
EHR launch means your app opens from inside Epic (in the clinician's session) with the patient/user context handed to it — that's a provider app. Standalone launch means the user starts your app from outside Epic and authorizes it themselves — for patients, that's against MyChart. Same OAuth 2.0 flow; the difference is who launches it and where the context comes from.
Do I Need SMART Backend Services, or a Regular SMART App?
If a human uses your app (clinician or patient), you want a regular user-facing SMART app (EHR launch or standalone) with the authorization-code flow. If it's server-to-server with no user — data pipelines, analytics, bulk export — you want Backend Services: a signed-JWT client-credentials grant with system/ scopes. Many products use both.
How Do SMART v2 Scopes Work?
A scope is context/Resource.operations. The context is patient/ (the launched patient), user/ (the logged-in user's access), or system/ (no user). The operations are letters — create, read, update, delete, search. So patient/Observation.rs = read + search Observations for one patient. Request the minimum you need.
Does Epic Support SMART on FHIR Write-Back?
Yes — Epic supports FHIR writes (e.g. creating Observations, DocumentReferences) through SMART on FHIR, subject to the scopes you're granted and the customer enabling them. Write access typically means more scrutiny in the security review, so we scope writes tightly to exactly the resources your workflow needs.
How Do I Get an Epic Sandbox to Test My SMART App?
Register your app for free on fhir.epic.com; you're issued a non-production client ID and can test your launch and FHIR calls against Epic's example "Try It" test patients — no real customer needed. When you're ready, you mark the app ready for production to use the production client ID. See our Epic integration overview.
Will My SMART App Pass Epic's / a Customer's Review?
The best predictor is conformance and least-privilege scoping. We build to US Core and validate against the ONC Inferno g10 test kit — the same bar a certified API must meet — and request only the scopes your workflow uses. That's what makes each health system's security/technical review fast instead of a back-and-forth.
Let's Build Your SMART App

Tell Us What Your SMART App Needs to Do.

Book a scoping call — we'll pick your launch type, scope it to least-privilege, and map the path from the Epic sandbox to a live customer. Reviewed by an integration engineer, not a sales queue.

+1 (669) 649-0706
hello@nirmitee.io

HIPAA-aware. We never share your details. No spam, ever.

Thanks — We've Got It.

A Nirmitee integration engineer will reach out within one business day.