Skip to content
FHIRVendors

FHIR Security Best Practices: Authorization, Audit and API Hardening

How to secure a FHIR API end to end: SMART on FHIR authorization, least-privilege scopes, signed JWT backend authentication, audit logging and the API flaws attackers actually exploit.

SecurityUpdated 6 min readBy the FHIR Vendors Editorial Team

Key takeaways

  • The FHIR specification deliberately leaves security to surrounding standards; in practice that means OAuth 2.0 profiled by SMART App Launch, TLS everywhere, and server-side enforcement of every access decision.
  • SMART v2 scopes (for example patient/Observation.rs) are finer-grained than v1 (patient/Observation.read) and can be narrowed further with search-parameter constraints such as an Observation category.
  • Backend systems should authenticate with asymmetric keys and signed JWT client assertions rather than shared client secrets.
  • Most real FHIR API breaches are authorization failures: object-level access checks that are missing, scopes that are too broad, and search or _include parameters that leak data outside the granted compartment.
  • AuditEvent and Provenance give you a FHIR-native audit trail, but they only help if they are written consistently and reviewed.

Where security lives in a FHIR system

FHIR defines resources and a RESTful API, but the core specification intentionally does not mandate a single authentication or authorization mechanism. Its security pages point implementers to established standards instead: TLS for transport, OAuth 2.0 and OpenID Connect for authorization and identity, and the SMART App Launch implementation guide for how those fit healthcare workflows. That design keeps the standard flexible, but it also means a FHIR server is only as secure as the decisions its implementers make around it.

A useful mental model is to separate four layers: transport (is the channel encrypted and the server authenticated?), client identity (which application is calling?), user and patient context (on whose behalf, and for which patient?), and data-level authorization (is this specific resource within what was granted?). Weaknesses usually appear in the last layer, because it is the one the FHIR server itself has to enforce on every read, search and write.

Scope of this guide

This is general technical guidance, not legal or compliance advice. Regulatory obligations depend on your role, jurisdiction and contracts; confirm them with qualified counsel and your compliance team.

OAuth 2.0 and SMART scopes

SMART App Launch profiles OAuth 2.0 for healthcare. Apps request scopes that describe the FHIR data they need, the authorization server issues an access token that reflects what the user (and policy) approved, and the FHIR resource server enforces those scopes. Scopes have three parts: a context prefix (patient/, user/ or system/), a resource type, and the permitted interactions.

AspectSMART v1 (1.0)SMART v2 (2.x)
Read access examplepatient/Observation.readpatient/Observation.rs (read + search)
Write access examplepatient/Observation.writepatient/Observation.cu (create + update); d for delete
Granularityread or write, or * for bothAny combination of c, r, u, d, s
Search constraintsNot definedOptional query parameters, e.g. patient/Observation.rs?category=...|laboratory
PKCERecommendedRequired, using the S256 method
SMART scope syntax, v1 versus v2. Servers that support v2 often accept v1 scopes for backward compatibility.

The v2 syntax matters for least privilege. A lab-results app can request only laboratory Observations rather than every Observation for the patient, which excludes vital signs, social history and other categories it has no reason to see. Whether a server honours those query-parameter constraints is a capability it advertises; if it does not, the app should expect a broader grant and the server owner should treat that as a known gap.

  • patient/ scopes restrict access to a single patient compartment chosen at launch.
  • user/ scopes grant access to whatever the signed-in user is permitted to see, which is usually far broader. Reserve them for clinician-facing apps that genuinely need cross-patient access.
  • system/ scopes are for backend services with no user present and should be issued only to vetted, contractually bound clients.

Backend services and signed JWT client assertions

Server-to-server integrations such as analytics pipelines, population-health jobs and Bulk Data exports use the SMART Backend Services profile. The client registers a public key (typically as a JWK Set URL) with the authorization server. To get a token, it signs a short-lived JWT with its private key and posts it using the OAuth client_credentials grant with client_assertion_type urn:ietf:params:oauth:client-assertion-type:jwt-bearer.

POST /token HTTP/1.1
Host: auth.example.org
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&scope=system%2FPatient.rs%20system%2FObservation.rs
&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
&client_assertion=eyJhbGciOiJSUzM4NCIsImtpZCI6...
Token request from a backend service (line breaks added for readability; the body is a single form-encoded string).
  • The JWT carries iss and sub (both the client_id), aud (the token endpoint URL), a unique jti and an exp no more than five minutes in the future. Servers should reject reused jti values.
  • The specification calls for RS384 or ES384 signatures. Keep private keys in a key management service or HSM, not in configuration files.
  • Publishing keys through a JWKS URL makes rotation routine instead of an outage.
  • Shared client secrets are easy to leak through logs and source control; avoid them for anything that touches production PHI.

Transport security and infrastructure basics

All FHIR traffic carrying health data should use TLS, and current practice is TLS 1.2 or later with modern cipher suites. Terminate TLS at a component you control and re-encrypt internally if traffic crosses networks you do not fully trust. Mutual TLS can add a strong client-binding layer for fixed B2B connections, though it complements rather than replaces OAuth.

  • Never put patient identifiers or other PHI in URL query strings that end up in proxy and access logs. FHIR supports POST-based search (POST [base]/Patient/_search) for exactly this reason.
  • Encrypt data at rest, including database snapshots, search indexes, NDJSON export files and message queues.
  • Set short access-token lifetimes and treat refresh tokens as long-lived credentials: bind them to the client, rotate them, and revoke them when a user or app is deprovisioned.
  • Rate-limit and size-limit requests; unbounded _count values and deep _include chains are an easy denial-of-service vector.

Least privilege and HIPAA Security Rule considerations

For US covered entities and business associates, the HIPAA Security Rule organises safeguards into administrative, physical and technical categories. Its technical safeguards map naturally onto FHIR API design: access control (scopes, roles, compartments), audit controls (AuditEvent and infrastructure logs), integrity (validation, versioning, Provenance), person or entity authentication (OpenID Connect, signed client assertions) and transmission security (TLS).

  • Run a risk analysis that explicitly includes the FHIR API surface, third-party apps and backend clients, not just the EHR database.
  • Grant the narrowest scopes that support the use case and review them when the app changes.
  • Separate duties: the team that registers apps should not be the only team reviewing their access.
  • Remember that patient-directed apps chosen by the patient under access-right rules are treated differently from vendors acting for the provider; involve compliance early when designing app vetting.

If you are scoping this work with a partner, the HL7 FHIR consulting page outlines what a security and architecture review typically covers.

Common FHIR API vulnerabilities

FHIR APIs suffer from the same classes of flaw as any REST API, with the twist that the data is unusually sensitive and the query language is unusually expressive. The OWASP API Security Top 10 is a good checklist; the items below are the ones that show up most often in healthcare API reviews.

VulnerabilityHow it appears in FHIRMitigation
Broken object level authorization (BOLA / IDOR)GET /Observation/123 returns a resource from another patient because the server checks the token is valid but not that the resource is in the patient's compartment.Enforce compartment and ownership checks on every read, vread, history and search result, not only on the request parameters.
Over-broad scopesApps request user/*.read or patient/*.* and receive it by default.Approve scopes per app, prefer v2 granular scopes, and let users deselect scopes at authorization time.
Search leakage_include, _revinclude or chained parameters return resources outside the authorized set, e.g. a Practitioner search that reveals patients through _revinclude.Apply authorization to every resource in the result Bundle, including included ones, and restrict chaining where it is not needed.
Inference through counts_summary=count or total in a Bundle reveals whether records exist even when content is filtered.Compute totals after authorization filtering, or omit them.
Mass assignment on writeA client updates meta.security, Patient.link or identifiers it should not control.Validate writes against profiles and server-side rules for protected elements.

Test the negative cases

Conformance suites such as Inferno check that a server does what it should. Security testing must also prove it refuses what it should not: cross-patient reads, expired tokens, scope escalation and manipulated references.

Teams building or exposing a FHIR API can find specialist help in the FHIR API development companies directory.

Frequently asked questions

Does FHIR include its own security protocol?

No. FHIR deliberately relies on existing standards. The usual stack is TLS for transport, OAuth 2.0 and OpenID Connect for authorization and identity, SMART App Launch for healthcare-specific profiles, and FHIR resources such as AuditEvent, Provenance and Consent for audit and policy data.

Should we support SMART v1 or v2 scopes?

New implementations should support v2 because it allows separate create, read, update, delete and search permissions and optional search constraints. Many servers also accept v1 scopes for older apps; if you do, map them carefully so that a v1 read scope does not silently grant more than the equivalent v2 scopes.

Is a client secret good enough for backend integrations?

It works, but asymmetric keys with signed JWT client assertions are the approach defined by SMART Backend Services. The private key never leaves the client, keys can be rotated through a JWKS endpoint, and nothing reusable is transmitted on each request.

What is the most common FHIR API security bug?

Broken object level authorization: the server validates the token but does not confirm that each returned resource belongs to the authorized patient or user. It is especially easy to miss in _include, _revinclude, history and chained search results.

Does storing a Consent resource enforce a patient's privacy choice?

Not by itself. Consent records the decision in a structured form, but your authorization server or FHIR server has to evaluate it when making access decisions for enforcement to happen.

References

  1. HL7 FHIR R4: Security
  2. HL7 FHIR R4: AuditEvent
  3. HL7 FHIR R4: Provenance
  4. HL7 SMART App Launch Implementation Guide
  5. HHS: HIPAA Security Rule
  6. OWASP API Security Project

FHIR® is a registered trademark of HL7 International. This guide is independent educational content and is not legal or compliance advice.

Related guides

Related FHIR services

Find the Right FHIR Integration Partner for Your Healthcare Project

Tell us what you need to build or connect. We review every request and share a short list of relevant vendors from our directory — no obligation.