← Writing
Healthcare EngineeringUpdated 24 Aug 2026 · 15 min read

Planning My First SMART on FHIR Integration

Early project notes on the product, authorization, data, security, testing, and operating decisions behind a SMART on FHIR R4 integration.

What does a SMART on FHIR integration need beyond OAuth? A defined launch workflow, verified patient and encounter context, minimum scopes, safe token handling, explicit FHIR profiles and versions, server-specific tests, PHI boundaries, auditable operations, and useful failure behavior. OAuth grants access; it does not decide the clinical workflow or make every FHIR server behave the same way.

This work is part of a patient-history platform with patient and clinic-admin applications, more than 150 conditional intake questions, and document capture. I am planning and beginning my first SMART on FHIR R4 integration. This is a decision framework shaped by early project work and current documentation, not a claim of long-standing FHIR specialization or a report of a completed multi-EHR rollout.

Reviewed 24 August 2026: HL7 SMART App Launch 2.2.0 and FHIR R4; current Epic on FHIR and Oracle Health Millennium sandbox and authorization documentation; and HHS Security Rule and minimum-necessary guidance.

Scope: this is an engineering planning guide, not legal advice. Using SMART, OAuth, encryption, audit logs, an EHR sandbox, or a vendor agreement does not by itself establish HIPAA compliance or production readiness.
Foundation

FHIR, SMART, and the EHR contract solve different problems

FHIR defines healthcare resources, search, and API interactions. SMART App Launch defines authorization, client authentication, discovery, scopes, and launch-context patterns around a FHIR server. The current published HL7 SMART App Launch guide is version 2.2.0, published against FHIR R4. HL7 also notes that SMART can work with other FHIR releases, so the SMART guide version and the server's FHIR version are separate compatibility decisions.

The third layer is the actual EHR environment. Its capability statement, SMART discovery document, supported profiles, search parameters, scope syntax, write policy, tenant endpoints, user permissions, and operational limits make up the integration contract. “Supports FHIR” and “supports SMART” are starting points, not acceptance criteria.

Primary sources: HL7 SMART App Launch 2.2.0, FHIR R4 CapabilityStatement, and FHIR R4 HTTP guidance.

Launch context

Choose the launch model and context rules together

EHR launch

The EHR opens the app with an issuer URL and opaque launch value. The authorization response may supply established context such as patient or encounter, depending on requested scopes and server capability.

Standalone launch

The app begins outside the EHR, identifies the target FHIR environment, and can request context such as patient selection through launch/patient.

Provider-facing

User identity, organization, role, selected patient, and encounter may all matter. A patient ID alone does not prove that a user may perform the intended action.

Patient-facing

The authenticated person and the patient resource in context can have a different relationship. The workflow must not assume they are always the same person.

Bind the returned issuer, tenant, authorized user, granted scopes, patient, and encounter to one server-side application session. Treat the launch value as opaque and short-lived. Never accept a patient or encounter from an ordinary query parameter as a substitute for authorized launch context, and never carry context from one issuer or organization into another session.

Encounter context is optional in many launches. If it is absent, the product needs an explicit fallback: require a supported selection flow, provide a safely authorized in-app selection, limit the workflow, or stop with a clear explanation. Do not guess the current encounter from the latest record or silently reuse the last session.

Primary source: HL7 scopes and launch context.

OAuth and PKCE

Protect the authorization flow, not only the API call

SMART App Launch uses the OAuth 2.0 authorization-code flow. HL7 2.2.0 says SMART apps must support Proof Key for Code Exchange (PKCE), with servers supporting S256 and not the plain method. PKCE binds the authorization request to the later code exchange; it does not replace state, exact redirect-URI validation, TLS, client registration, or issuer and audience checks.

  1. Discover the environment from [fhir-base]/.well-known/smart-configuration instead of assuming one vendor-wide authorization endpoint.
  2. Create unpredictable state and a fresh PKCE verifier per authorization attempt; bind both to the initiating browser session.
  3. Send the authorization request with the exact registered redirect URI, intended FHIR base as aud, required launch value, and minimum scopes.
  4. On callback, reject missing or mismatched state, unexpected issuer or tenant, reused codes, invalid redirect context, and expired attempts before exchanging the code.
  5. Inspect the token response and granted scope. Treat patient, encounter, token lifetime, and refresh capability as returned facts rather than requested guarantees.

For a server-backed web app, keep the code exchange and tokens on the server and give the browser an application session rather than a bearer token. Public browser or native clients need an architecture appropriate to their inability to protect a static secret, short token exposure, platform-secure storage where available, and no tokens in URLs, analytics, logs, crash reports, support tickets, or source control.

Refresh tokens are optional and more durable than access tokens. Request online_access or offline_access only when the workflow requires it; store any granted refresh token as a high-value secret, rotate it when the server returns a replacement, handle revocation, and remove it when the integration is disconnected. A failed refresh should send the user through a new authorization flow, not an infinite retry loop.

Primary source: HL7 launch and authorization flow.

Scopes and minimization

Request an operation contract, then verify the grant

SMART 2.x scopes can describe resource types and actions such as create, read, update, delete, and search. For example, patient/Observation.rs requests patient-context read and search access for Observation. Some deployed environments use different SMART versions or vendor-specific supported scope sets, so build the requested scope set from the target environment's documented capability instead of assuming every server accepts the newest shorthand.

Create a scope-to-feature matrix before registration:

  • feature and user role;
  • launch, patient, encounter, or system context;
  • resource type and exact read, search, create, or update operation;
  • required search parameters and profile;
  • behavior when the scope is not granted or results are filtered;
  • whether data is displayed transiently, stored, exported, or written back.

Inspect the granted scope value. The authorization server may grant less than requested, and EHR role permissions can narrow the effective result again. A successful token response therefore does not guarantee that a particular resource, patient, search, or write is allowed.

HL7 recommends requesting only access needed for the app. HHS describes minimum necessary as a Privacy Rule standard that generally limits uses, disclosures, and requests for PHI to the intended purpose. Whether and how that rule applies is an organizational determination, but a narrow feature-to-scope and field-to-purpose map is also sound engineering: it reduces exposed data and makes access review more concrete.

Primary sources: HL7 SMART scopes and HHS minimum-necessary guidance.

Backend services

Do not stretch an interactive launch into a batch credential

A scheduled import, reconciliation worker, or population-level job has no interactive user and should be evaluated as a separate backend-service integration. SMART Backend Services uses pre-authorized system/ scopes and confidential asymmetric client authentication with a registered public key. It is not an indefinitely reusable access token copied from an EHR launch.

  • Register and rotate signing keys; keep private keys out of application images, repositories, logs, and general developer access.
  • Discover the token endpoint for each FHIR base and validate the audience used for the client assertion.
  • Authorize the smallest system scopes and tenant boundary needed by the job.
  • Use short-lived access tokens, bounded queues and retries, checkpoints, and idempotent writes.
  • Keep human-launched and system-launched credentials, audit identities, failure paths, and revocation procedures separate.

A vendor can support interactive SMART launch while limiting backend-service resources or requiring additional onboarding. Confirm the exact combination rather than treating “SMART supported” as one capability flag.

Primary source: HL7 SMART Backend Services.

FHIR contract

Map resources, profiles, terminology, and versions explicitly

A patient-history concept rarely maps cleanly to one resource. The workflow may involve Patient, Questionnaire, QuestionnaireResponse, Condition, AllergyIntolerance, Medication-related resources, Observation, DocumentReference, and Encounter. The server's supported profiles and write behavior—not the resource name alone—determine whether the mapping works.

For every field and operation, record:

  • FHIR release, resource, profile canonical URL, required extensions, cardinality, and terminology binding;
  • identifier system, reference strategy, units, code system, and handling of absent or unknown values;
  • source of truth, conflict policy, version-aware update behavior, and whether writes are create, update, conditional create, or transaction;
  • required search parameters, pagination, inclusion behavior, sorting assumptions, and server limits;
  • unsupported-field behavior, partial-result behavior, and preservation of data the application does not understand.

Read the server CapabilityStatement and vendor API documentation, but verify behavior with tests. Send and accept the correct FHIR media types; where needed, use the fhirVersion media-type parameter. Do not deserialize an R4B or R5 resource into an R4 model merely because the top-level resource name matches.

Maintain a compatibility matrix by EHR product, customer environment, FHIR base, FHIR release, SMART version, profile or API version, feature, and last verified date. Fail clearly when the environment is outside the supported matrix instead of attempting a best-effort clinical write.

Testing

Use sandboxes to learn the contract, not certify production

Official EHR sandboxes are valuable, but they represent vendor test data and a subset of real deployment behavior. Epic documents separate non-production client IDs, a public sandbox, LaunchPad, and workflows that still require testing with a customer in a non-production environment. Oracle Health documents an open read-only R4 sandbox, an authenticated secure sandbox registered through code Console, explicit per-resource scopes, and no wildcard scopes in its current authorization framework.

Those differences are the point: the integration needs vendor adapters and environment-specific evidence. Passing one public sandbox does not prove another EHR, another customer tenant, or a production configuration will behave the same way.

Authorization

Test bad state, bad PKCE verifier, reused and expired code, exact redirect URI, denied consent, partial scope grant, token expiry, refresh rotation, revocation, and wrong issuer or audience.

Context

Test missing patient, missing encounter, patient switch, provider versus patient user, cross-tenant session reuse, stale browser tabs, and relaunch behavior.

FHIR data

Test empty and partial bundles, pagination, unknown extensions, missing references, terminology variation, duplicate identifiers, optimistic concurrency, unsupported search, and malformed resources.

Operations

Test 401, 403, 404, 409, 412, 429, and 5xx responses; timeouts; retry limits; partial write outcomes; vendor maintenance; and safe user recovery.

Use synthetic patients and vendor-provided test identities in development. Do not copy production PHI into local fixtures, recordings, tickets, or CI merely to make a sandbox scenario realistic. Before go-live, repeat the supported workflow with the customer and EHR vendor in the designated non-production environment, then run a controlled production smoke test with approved identities and rollback criteria.

Official EHR references: Epic OAuth 2.0 and sandbox documentation and Oracle Health SMART build and test guide.

Errors and write safety

Make failures safe for patients, users, and operators

FHIR servers commonly return an OperationOutcome for errors, but the HTTP status, response body, and vendor documentation must be interpreted together. Do not show a raw clinical payload or server stack trace to the user, and do not convert every 403 or 404 into “patient not found.” The server may be hiding a resource the current principal cannot access.

  • Classify errors as reauthorization, permission, missing context, validation, conflict, throttling, transient dependency, or unsupported capability.
  • Use bounded retry with backoff only for operations known to be safe. A network timeout after a create can mean the server committed the resource but the client missed the response.
  • Use conditional create, stable identifiers, transaction bundles, version-aware updates, or another server-supported strategy to prevent duplicates and lost updates.
  • Persist a write intent and outcome separately so operators can reconcile unknown or partial states without repeating the entire workflow.
  • Give users an actionable, non-sensitive message and a correlation reference; route technical detail to a restricted support path.

Primary source: FHIR R4 OperationOutcome.

PHI and audit boundary

Log the integration without copying the chart into telemetry

FHIR responses, patient and encounter identifiers, search parameters, free text, documents, OAuth tokens, and launch context can be PHI or security-sensitive. Keep them out of general application logs, analytics, session replay, traces, error monitoring, alert messages, build output, and ordinary support tools by default.

An operational event can record timestamp, environment and tenant, actor or workload identity, feature, resource type, operation, outcome class, latency, retry count, EHR request ID, and an internal correlation reference without recording the resource body, token, patient name, clinical text, or full request URL. If record-level identifiers are required for an approved audit purpose, place them in a separately protected, access-controlled audit store with defined retention and review—not in broad developer telemetry.

HHS Security Rule technical safeguards include access control, audit controls, integrity, person or entity authentication, and transmission security for systems containing or using ePHI. The exact safeguards and organizational obligations require risk analysis and review by the responsible privacy, security, compliance, and legal owners. An application log is not automatically a sufficient audit record, and an audit record should not become an unnecessary PHI replica.

Define who can connect or disconnect an EHR, change scopes or mappings, launch as a user, read or write each resource class, access restricted integration diagnostics, rotate backend keys, replay a failed job, and approve a production support investigation. Test those controls and review the evidence.

Primary source: HHS Summary of the HIPAA Security Rule. For telemetry design, see Configure Sentry Without Leaking PHI and Centralized Cloud Audit Logging.

Delivery checklist

What I would require before enabling a workflow

  1. Define the user, launch model, issuer selection, patient and encounter rules, and behavior when context is absent or changes.
  2. Record SMART and FHIR versions, discovery metadata, profiles, search parameters, terminology, write behavior, and customer-specific variation.
  3. Build the feature-to-scope matrix; inspect granted scopes and test filtered and denied operations.
  4. Threat-model authorization, PKCE, redirect URIs, session binding, token storage, refresh, revocation, backend keys, and tenant separation.
  5. Define source of truth, identifiers, duplicate prevention, version conflicts, partial writes, retries, reconciliation, and rollback.
  6. Map PHI across browser, API, database, queue, cache, log, trace, alert, support, backup, and deletion paths.
  7. Pass automated contract and negative tests, the official vendor sandbox, the customer non-production environment, and a controlled production verification.
  8. Prepare runbooks, ownership, restricted diagnostics, audit review, credential rotation, vendor escalation, downtime behavior, and disconnect procedures.

The useful deliverable is not a generic claim that the app is “FHIR compatible.” It is a versioned statement of which launch paths, users, resources, profiles, operations, EHR environments, and failure modes the product supports—and evidence that each one was tested.

Project context: this remains planning and early work on my first SMART on FHIR R4 integration, within a healthcare intake platform I lead as technical product owner and technical lead. Read the anonymized case study.

Planning a healthcare integration?

I can help with product discovery, workflow mapping, architecture, delivery planning, and the evidence needed for a safe handoff to implementation.

Start a project inquiry

Please do not send PHI by email.