SMART on FHIR Authentication: A Developer's Complete Guide
How SMART on FHIR authentication works — EHR launch vs standalone launch, OAuth 2.0 scopes, token refresh, and the implementation details that trip up engineering teams.
What Is SMART on FHIR?
SMART on FHIR (Substitutable Medical Apps, Reusable Technologies on FHIR) is an open standard for authorizing third-party healthcare applications to access EHR data. It extends OAuth 2.0 with healthcare-specific context — the current patient, encounter, and clinical user are passed as part of the authorization flow.
When a clinician opens your custom application from within Epic's Hyperspace, the EHR sends a launch token to your app. Your app exchanges this token for an access token scoped to that specific patient and session. This is the SMART EHR Launch flow.
The Two Launch Flows
EHR Launch (clinician-facing apps)
The EHR initiates the launch. The user clicks a link inside Epic, the EHR passes a launch parameter to your app, and your app completes the OAuth handshake.
// Step 1: EHR redirects to your launch URL with iss + launch params
// https://yourapp.com/launch?iss=https://epic.org/fhir&launch=abc123
// Step 2: Your app redirects to the EHR's authorization endpoint
const params = new URLSearchParams({
response_type: "code",
client_id: "your-client-id",
redirect_uri: "https://yourapp.com/callback",
scope: "launch openid fhirUser patient/Patient.read patient/Observation.read",
state: generateState(),
aud: issUrl,
launch: launchToken,
});
window.location.href = `${authEndpoint}?${params}`;
Standalone Launch (patient-facing apps)
The app initiates independently. The user opens your app, selects their provider, and the app discovers the EHR's FHIR endpoint via /.well-known/smart-configuration.
Scopes — the Part That Fails App Orchard Review
SMART scopes define exactly which FHIR resources your app can access, following the pattern [context]/[ResourceType].[operation]:
patient/Patient.read— current patient recordpatient/Observation.read— observations for the current patientuser/Appointment.write— write appointments on behalf of the useroffline_access— needed for background processing after the user closes the app
The key mistake: over-requesting scopes. Epic and Cerner audit scope lists during App Orchard review. Request only what you actually use. See the Epic App Orchard approval guide for how scope declarations affect the review timeline.
Token Expiry and Refresh
Epic tokens expire in 8 hours. Cerner's expire in 570 seconds (9.5 minutes). Handle refresh proactively:
import FHIR from "fhirclient";
FHIR.oauth2.ready().then(async (client) => {
const { token_at, expires_in } = client.state.tokenResponse;
const expiresAt = token_at + (expires_in * 1000);
if (Date.now() > expiresAt - 300_000) {
await client.refresh(); // refresh 5 minutes early
}
const patient = await client.patient.read();
});
Any application using SMART on FHIR handles real patient PHI. It must satisfy all HIPAA technical safeguards and have a signed BAA with the health system before going live.
The EHR / EMR Middleware service handles SMART on FHIR authentication so your application code focuses on clinical workflows, not OAuth edge cases.
Related Service
EHR / EMR Middleware
Deep-dive into our engineering approach, capabilities, and technical specifications.
Written by Sheharyar Amin
Founder & Lead Engineer, Opexia