Skip to main content

SMART on FHIR

SMART on FHIR is a standard that enables healthcare applications to securely access patient data across different EHR systems. It builds upon OAuth 2.0 and OpenID Connect to provide healthcare-specific authentication and authorization.

Overview

SMART on FHIR is an open standard developed by the SMART Health IT project in collaboration with HL7. It allows third-party applications to launch from within EHR systems or standalone, while maintaining consistent security and user experience across different healthcare platforms.

Key Features:

  • EHR Integration: Applications can launch directly from within EHR systems
  • Standardized Scopes: Healthcare-specific permissions using FHIR resource types
  • Patient Context: Applications receive context about which patient's data to access
  • User Context: Applications know which user (patient, practitioner) is authenticated
  • Interoperability: Same app works across different EHR vendors (Epic, Cerner, etc.)

SMART Launch Flows

SMART on FHIR supports two primary launch patterns:

1. EHR Launch (Contextual Launch)

The application is launched from within an EHR system, automatically receiving context about the patient and user.

Launch URL Format:

https://app.example.com/launch?
iss=https://api.haste.health/w/{tenant}/{project}/api/v1/fhir/r4
&launch=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Authorization Request:

GET /w/{tenant}/oauth/api/v1/authorize?
response_type=code&
client_id=smart-app-id&
redirect_uri=https://app.example.com/callback&
scope=launch patient/*.read&
state=random-state&
aud=https://api.haste.health/w/{tenant}/{project}/api/v1/fhir/r4&
launch=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

2. Standalone Launch

The application launches independently, and the user selects which patient's data to access.

SMART Scopes

SMART on FHIR defines a structured scope syntax that combines permissions with FHIR resource types.

Scope Syntax

<context>/<resource>.<permission>

Components:

  • Context: Who is accessing the data (patient, user, system)
  • Resource: FHIR resource type (Patient, Observation, etc.) or * for all
  • Permission: Access level (read, write, or * for both)

Scope Categories

1. Clinical Scopes (Patient Context)

Access data for the currently selected patient:

ScopeDescription
patient/*.readRead all patient compartment resources
patient/*.writeWrite all patient compartment resources
patient/*.*Full read/write access to patient compartment
patient/Patient.readRead Patient demographics
patient/Observation.readRead Observations (labs, vitals, etc.)
patient/Condition.readRead Conditions (diagnoses)
patient/MedicationRequest.readRead medication orders
patient/AllergyIntolerance.readRead allergies
patient/Immunization.readRead immunization history
patient/DiagnosticReport.readRead diagnostic reports
patient/Procedure.readRead procedures
patient/DocumentReference.readRead clinical documents
patient/CarePlan.readRead care plans
patient/Goal.readRead patient goals
patient/Encounter.readRead encounter history

2. User-Level Scopes

Access data across all patients the user has access to:

ScopeDescription
user/*.readRead all resources the user can access
user/*.writeWrite all resources the user can access
user/*.*Full read/write access for the user
user/Patient.readRead all patients user can access
user/Observation.readRead all observations user can access
user/Practitioner.readRead practitioner information
user/Organization.readRead organization information

3. System-Level Scopes

Access for backend services (Client Credentials flow):

ScopeDescription
system/*.readRead all resources (backend access)
system/*.writeWrite all resources (backend access)
system/*.*Full read/write system access
system/Patient.readRead all patients (no user context)
system/Observation.readRead all observations (no user context)

4. Launch Scopes

Control launch context and behavior:

ScopeDescription
launchRequired for EHR launch flow
launch/patientRequest patient picker for standalone launch
launch/encounterRequest encounter context
online_accessRequest refresh token for long-term access
offline_accessRequest refresh token for offline/background access

5. OpenID Connect Scopes

Standard OIDC scopes for user identity:

ScopeDescription
openidRequired for OIDC authentication
profileUser's name, picture, etc.
emailUser's email address
fhirUserFHIR resource representing the user (Patient, Practitioner, etc.)

Token Response with Context

When using SMART on FHIR, the token response includes additional context information:

{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "patient/Patient.read patient/Observation.read",
"patient": "Patient/123",
"encounter": "Encounter/456",
"refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Context Parameters:

ParameterDescriptionExample
patientFHIR Patient resource IDPatient/123
encounterCurrent encounter contextEncounter/456
fhirUserFHIR resource for authenticated userPractitioner/789 or Patient/123
tenantTenant identifier (if multi-tenant)org-acme-health
need_patient_bannerWhether to show patient bannertrue
intentLaunch intent (reconcile-medications, etc.)reconcile-medications

SMART Configuration Discovery

Applications discover SMART capabilities via the .well-known endpoint:

Request:

GET /.well-known/smart-configuration HTTP/1.1
Host: api.haste.health

Response:

{
"issuer": "https://api.haste.health",
"authorization_endpoint": "https://api.haste.health/w/{tenant}/oauth/api/v1/authorize",
"token_endpoint": "https://api.haste.health/w/{tenant}/oauth/api/v1/token",
"token_endpoint_auth_methods_supported": [
"client_secret_basic",
"client_secret_post",
"private_key_jwt"
],
"registration_endpoint": "https://api.haste.health/w/{tenant}/oauth/api/v1/register",
"scopes_supported": [
"openid",
"profile",
"email",
"fhirUser",
"launch",
"launch/patient",
"launch/encounter",
"online_access",
"offline_access",
"patient/*.read",
"patient/*.write",
"user/*.read",
"user/*.write",
"system/*.read",
"system/*.write"
],
"response_types_supported": [
"code"
],
"capabilities": [
"launch-ehr",
"launch-standalone",
"client-public",
"client-confidential-symmetric",
"context-ehr-patient",
"context-ehr-encounter",
"context-standalone-patient",
"context-standalone-encounter",
"permission-offline",
"permission-patient",
"permission-user",
"permission-v2"
],
"code_challenge_methods_supported": [
"S256"
],
"grant_types_supported": [
"authorization_code",
"refresh_token",
"client_credentials"
]
}

SMART Capabilities

Supported Capabilities

Haste Health supports the following SMART capabilities:

CapabilityDescriptionSupported
launch-standaloneSupports standalone launch✅ Yes
client-publicSupports public clients (no secret)✅ Yes
client-confidential-symmetricSupports confidential clients with secret✅ Yes
context-standalone-patientPatient picker in standalone launch✅ Yes
permission-offlineSupports offline_access scope✅ Yes
permission-patientSupports patient/* scopes✅ Yes
permission-userSupports user/* scopes✅ Yes
permission-v2SMART v2 scope syntax✅ Yes

Common Use Cases

Patient Portal

// Patient viewing their own data
scope: 'openid profile patient/Patient.read patient/Observation.read patient/Condition.read patient/MedicationRequest.read online_access'

Clinical Decision Support

// CDS app launched from EHR
scope: 'launch patient/Patient.read patient/Observation.read patient/Condition.read patient/MedicationRequest.read patient/AllergyIntolerance.read'

Population Health

// Analytics dashboard for clinicians
scope: 'openid profile user/Patient.read user/Observation.read user/Condition.read user/Encounter.read'

Research Data Export

// Backend system for de-identified data
scope: 'system/Patient.read system/Observation.read system/Condition.read system/Procedure.read'

Resources