FHIR will serve a patient record to anyone the server lets through, because the standard states plainly that it isn't a security protocol. That one fact shapes every piece of healthcare API development: the interoperability comes from the specification, and the protection has to come from what you build around it.
What follows takes the layers in the order you'll meet them: the data model, authorization with SMART on FHIR, the HIPAA technical safeguards, and audit logging.
What healthcare API development actually covers
It means exposing clinical and administrative data as FHIR resources over HTTPS, then controlling who can read or write each one. FHIR defines the content and the exchange. Authentication, access control and auditing are yours to supply. Our overview of healthcare software development covers the wider project this work sits inside.
The unit of exchange is the resource. According to the HL7 FHIR overview, every resource is assembled from reusable datatypes, carries a common set of metadata and includes a human-readable part. Resources are available in XML and JSON, and an extension mechanism handles content the core set doesn't cover.
One resource is worth knowing early: CapabilityStatement, which describes the interfaces a server exposes. Clients read it to learn what your API supports before they send a single request.
The data has plenty of consumers. Tools like the ones in our piece on clinical decision support systems need patient data from somewhere, and so do the devices covered in healthcare IoT software. Each consumer is another client your authorization model has to describe.
Why FHIR leaves security to you
FHIR's security page says the specification is not a security protocol and "does not require or rely on any security being in place." A server that implements the REST API faithfully can still be wide open. Everything below is the work of closing it.
The same page, HL7's FHIR security guidance, sets out the baseline. Production exchange should run over TLS. Users and clients must be authenticated, with OAuth recommended for web-centric systems and OpenID Connect added when you need the identity of the end user.
Authorization is where teams get caught. FHIR supports both role-based and attribute-based access control, using things like security labels, purpose of use and patient consent. But it defines no resources for administering users or access rules, so that machinery is yours to build.
The risk sits in the search surface. A permission check that covers a direct read but forgets a search using _include can return the same record by another route. FHIR's guidance lists chained searches, bundles, batch and transaction processing and break-the-glass access as places to check.
How SMART on FHIR handles authorization
SMART on FHIR is the OAuth 2.0 profile most FHIR deployments use to decide which app can see which data. An app proves who it is, the user or the system grants a defined set of scopes, and the server issues a short-lived token limited to those scopes. The SMART App Launch specification defines each step.
Choosing a launch type
An EHR launch starts inside the EHR. It opens your app's registered URL with the FHIR base address and an opaque launch ID, which your app echoes back in its authorization request.
A standalone launch starts outside the EHR with no such ID. The app declares the context it needs through scopes such as launch/patient, and the server's authorization step establishes that context, sometimes by showing the user a patient picker.
Requesting the narrowest scopes
Resource scopes name a resource type and the permissions wanted, as in patient/Observation.rs or patient/Patient.r. The specification tells apps to request the minimum necessary, and it's worth enforcing that in code review. A scope list that starts broad never gets narrower.
PKCE, tokens and client types
Every SMART app must support PKCE, and servers must support the S256 method and refuse plain. The spec also requires an aud parameter naming the FHIR server, so a token can't be handed to a counterfeit one, and a state value the app validates on return.
Access tokens should live no longer than an hour, and token responses must carry Cache-Control: no-store. A stolen token then expires quickly.
Client type decides how the app authenticates. Browser apps and distributed native apps can't hold a secret, so they're public clients with no authentication at the token endpoint. Server-side apps are confidential clients and must authenticate, with asymmetric methods preferred where available.
If your integration is a backend service rather than a person using an app, treat it as a confidential client from day one. Retrofitting client authentication later means touching every integration.
What the HIPAA technical safeguards ask of an API
The Security Rule's technical safeguards in 45 CFR 164.312 set five standards: access control, audit controls, integrity, person or entity authentication and transmission security. Only two of the implementation specifications are required, unique user identification and an emergency access procedure. The rest are addressable.
| Standard | Specification status | What it means for your API |
|---|---|---|
| Access control | Unique user ID and emergency access required; automatic logoff and encryption addressable | Every caller gets its own identity, so shared credentials across integrations are out. Build a break-the-glass path. |
| Audit controls | No specifications listed | Record and review activity in systems that handle ePHI, including reads. |
| Integrity | Mechanism to authenticate ePHI addressable | Guard records against unauthorized change or deletion. |
| Person or entity authentication | No specifications listed | Confirm the caller is who it claims to be, which is what OAuth client authentication does. |
| Transmission security | Integrity controls and encryption addressable | Protect data on every network hop, not only the public one. |
"Addressable" reads like "optional," and that's a trap. FHIR's own guidance says production exchange should use TLS, so skipping transport encryption would be hard to defend to anyone reviewing your design.
The code is only part of compliance. Our guide to HIPAA compliant app development covers the wider work around it.
Logging access without creating a second leak

Photo by Aleks Magnusson on Pexels
FHIR gives you two resources for the paper trail. AuditEvent records security and privacy events, and Provenance tracks the origin, authorship and history of a resource.
Logs need the same care as the records. The FHIR security page warns that HTTP logs, even the URLs alone, can be as sensitive as the resources themselves. A search URL containing a patient's name or date of birth is PHI sitting in a web server log that nobody locked down.
So decide up front what goes into a log line. Store resource IDs and the caller's identity, keep identifying search parameters out of the stored URL, and restrict who can read the logs to the same standard as the data.
A build order for the first release
Teams tend to build endpoints first and bolt security on afterward. Reversing that order is cheaper, and it looks like this:
- List every client that will call the API and decide whether each is a public or confidential client.
- Stand up TLS and the authorization server before the first endpoint returns real data.
- Write access rules that cover reads, searches, includes and batch requests together.
- Turn on audit logging before any real patient data arrives.
Products with several front ends feel this most. We designed and built the website, members portal and mobile app for OptimalMD, and with that many front doors a single, consistent authorization model matters more than any individual endpoint. If you're scoping an API inside a larger product, our apps and SaaS team works on exactly that.
Before launch, test with a client holding only the narrowest scope it needs. Run searches, includes and batch requests as that client and confirm nothing outside its scope comes back.
Frequently asked questions
How does an app get the user's identity in SMART on FHIR?
It requests the openid and fhirUser scopes. The token response then includes an id_token identifying the user.
Can a refresh token be used to widen an app's access?
No. A refresh request can ask only for a strict subset of the original grant, and the refresh token is bound to the same client.
What should a FHIR server return when access is denied?
FHIR's security guidance offers several options: an empty Bundle, a 404, a 403 or a 401. Each leaks a different amount of information about whether the record exists, so pick one deliberately rather than by default.
Do offline apps need a refresh token?
Only if they request the offline_access scope, which asks for a refresh token. The server must also allow it for that client type.
Cover photo by Startup Stock Photos on Pexels
Sources
- FHIR Overview — HL7 International
- FHIR Security — HL7 International





























