HAPI FHIR security hardening

A HAPI FHIR server is not secure out of the box for health data. This page covers the decisions, build sequence, effort drivers and verification steps for hardening it, and what to hand over.

On this page

Why HAPI FHIR security hardening takes more than switching the database

Hardening a HAPI FHIR server for health data means replacing the embedded H2 database, adding transport security, closing the operations endpoints and the testing UI, enabling audit logging, and separating data where your organization needs it. Teams often start from the JPA server starter with its defaults, which gets a server running quickly but leaves each of those items open. The database swap is the most visible step, and it is the one most often mistaken for the whole job.

HAPI FHIR does not ship a single security layer. It provides building blocks: authentication interceptors, the AuthorizationInterceptor, consent and search narrowing interceptors, CORS support and BALP audit logging. Your team must wire in, configure and test each one. A caller that passes authentication can still reach resources it should not see unless authorization rules and search narrowing are in place, so the blocks have to work together. The security design is yours to own from the first sprint, including which blocks you use, the order in which they run, and what each one is expected to refuse.

The work is spread across four layers that rarely share a single owner. The database holds the data, along with its encryption, backup and access settings, and the choice between PostgreSQL and Microsoft SQL Server changes which controls you configure. The container or servlet layer, whether it is the hapiproject/hapi Docker image, a WAR on Tomcat, Jetty or Wildfly, or a Helm release on Kubernetes, holds TLS termination, exposed ports, management endpoints and the testing UI. The interceptors enforce access and audit rules inside the application. The operating model covers who may change configuration, how secrets are rotated and how logs are retained. A gap in any one layer can undermine the others, so review them together.

Identity and authorization rules deserve their own design. The sibling topic on authentication and authorization integration covers how to connect an identity provider and write AuthorizationInterceptor rules, so this section only flags the decisions to make early. The first is scope: which resource types, operations and data partitions each caller group may reach. The second is whether partitioning should separate tenants, data sources or regions, since the partition model shapes the rules you write. Ask your security team and identity provider owner to settle both before the first environment is built, because partition boundaries are harder to change once data has been loaded.

Which HAPI FHIR components carry the security configuration

HAPI FHIR does not ship a single security layer. Protection is spread across the database, the servlet or Spring Boot layer, the testing UI, interceptors and partitioning, so each one needs a deliberate decision. The cards below set out what each component controls and what its default leaves open.

JPA server starter and embedded H2

The JPA server starter is the packaged FHIR server most teams begin with, and it defaults to an embedded H2 database. H2 is suitable for evaluation, not for clinical data in production. Confirm the database property keys for your version, then replace the default with a production database before any patient data is loaded.

Production database connection

The starter supports PostgreSQL and Microsoft SQL Server for production, and does not support MySQL. Check that the datasource credentials come from a secrets store rather than a plain configuration file, that the database account has only the privileges the schema needs, and that connections are encrypted in transit. Confirm the exact property keys and driver versions against your release.

Servlet container or Spring Boot TLS

TLS termination happens in the servlet container, in Spring Boot, or at a reverse proxy or load balancer in front of it. Decide where the certificate lives and whether traffic is re-encrypted between the proxy and the server. Verify the protocol versions and cipher settings in the layer you choose, and confirm that plain HTTP is closed on every listener, including management endpoints.

Testing UI and exposed endpoints

The bundled testing UI and the metadata and operation endpoints are useful for development but expose the server's surface to anyone who can reach it. Decide whether the UI is disabled in production, and review which operations, such as bulk export or the $ operations, remain reachable. Confirm the relevant property keys for your version and test each endpoint without credentials after the change.

Authentication and AuthorizationInterceptor

HAPI FHIR provides authentication interceptors and the AuthorizationInterceptor as building blocks, not a finished access model. The interceptors decide who a request belongs to and which resources and operations that caller may read or write. Map roles from your identity provider to explicit rules, deny by default, and test negative cases such as cross-patient reads and unauthorized writes.

BALP audit logging interceptor

The BALP audit logging interceptor records FHIR access events in the Basic Audit Log Pattern, which is the audit model most teams map to their access logging requirements. Decide where audit records are stored, how long they are kept, and who can read them. Confirm that the interceptor records both successful and denied requests, and test that a read by a clinician leaves a traceable entry.

Partitioning for data separation

JPA partitioning assigns each resource to a partition, which can separate tenants, data sources or regions. It is a data-separation mechanism, so it only protects data if access rules are also bound to partitions. Check that every search, read and write resolves to the correct partition, and confirm the partition configuration and any cross-partition behavior for your release.

Decisions to settle before changing the server

This table compares the five decisions that shape a HAPI FHIR hardening project, with the option, when it fits and what it costs to run. Read each row before changing configuration, because several choices affect the database, the network path and the audit trail at the same time. The main takeaway is that the database and TLS choices should be settled first, since the rest of the work depends on them.

DecisionOptionsWhen it fitsOperational cost
Production databasePostgreSQL or Microsoft SQL Server (MySQL is not supported by the starter)PostgreSQL fits teams already running it; SQL Server fits organizations with existing SQL Server operations and licensing. Replacing the default embedded H2 database is required for production.Database licensing or hosting, backups, schema upgrades on each HAPI release, and DBA time. Confirm the database version against the release you plan to run.
TLS termination pointAt a reverse proxy or load balancer, or inside the application containerProxy termination fits sites with a central certificate process and existing WAF or ingress. Termination inside the container fits deployments with no shared edge, or where traffic must stay encrypted to the JVM.Certificate renewal and rotation in one place versus several. Proxy termination needs trusted forwarding headers configured so the server sees the correct scheme and client address.
Testing UI and operation endpointsDisable, or restrict by network or authenticationDisable the testing UI in any environment that holds real patient data. Keep operation endpoints only where administrators need them, behind authorization.Low build cost, but teams that rely on the UI for support or clinical testing need an alternative such as a separate non-production instance.
BALP audit logging destinationExisting log platform (SIEM or log analytics) or local log files onlyUse the existing platform when the security team already monitors and retains logs centrally. Local files alone fit only where another process ships and protects them.Log volume and retention costs, a shipping agent to maintain, and access controls on the audit store. Confirm retention periods with your compliance owner.
Data separation approachPartitions within one deployment or separate deployments per datasetPartitions fit multitenancy or regional grouping within one trust boundary. Separate deployments fit cases where tenants need isolated databases, credentials or upgrade windows.Partitions keep one platform to operate but add query and access-control design work. Separate deployments multiply infrastructure, patching and monitoring effort.
JDK versionThe JDK required by the HAPI FHIR release you runHAPI FHIR 8.2.0 requires JDK 17. Pick the release first, then confirm its JDK requirement in the release documentation.A JDK upgrade touches the base image, build pipeline and every custom interceptor, so it should be planned with the release upgrade.

How to harden a HAPI FHIR JPA server step by step

This sequence moves a HAPI FHIR JPA server from its default embedded setup to a production configuration that controls access, encrypts traffic, records who reads patient data, and separates data where required. Each step ends with a check your team can run and record before moving on.

  1. Pin the release and Java runtime

    Choose one HAPI FHIR release and build the server against it. Confirm the Java requirement for that exact version in the HAPI FHIR versions documentation before you choose a JDK, because the requirement changes between releases. For example, the documentation states that HAPI FHIR 8.2.0 requires JDK 17, but your pinned version may differ. Record the release, JDK build and starter or WAR artifact in your configuration repository. Done means the server starts on the pinned JDK and the server's FHIR metadata endpoint reports the expected software version. Any later upgrade starts from this recorded baseline.

  2. Move the database off embedded H2

    The JPA server starter defaults to an embedded H2 database. Replace it with PostgreSQL or Microsoft SQL Server, the two production databases the starter supports. Create a dedicated database account for the application with only the privileges the schema and data changes need, and keep schema administration under a separate account. Set up scheduled backups and test a restore into a separate environment. Done means the server runs against the external database, a test resource written through the API appears in the database tables, and a restore from the most recent backup returns that resource. Confirm the schema-management approach for your release before the first production start.

  3. Configure TLS and certificate handling

    Terminate TLS at the server or at a reverse proxy in front of it, and use a certificate issued by your internal or public certificate authority with a full chain. Disable plain HTTP on any interface that clients can reach, or redirect it to HTTPS only where your policy allows. Define how certificates are renewed and where private keys are stored, and confirm the protocol versions and cipher suites your security team approves. Done means a TLS handshake from a test client completes with the expected certificate chain and protocol version, and a plain HTTP request to the FHIR base URL is refused or redirected. Keep the handshake output as evidence for your configuration record.

  4. Restrict CORS to known origins

    Cross-origin resource sharing lets browser applications call the server from other domains. Replace any permissive setting with an explicit list of origins that your clinical or integration applications use, and leave out wildcards. Review which HTTP methods and headers are allowed for each origin. Done means a preflight request from an origin on the list receives the expected allow headers, and a preflight request from an origin that is not on the list receives no allow-origin header. Test with at least one browser-based client and one origin that should be rejected. Record the list so that adding an origin later requires a documented change.

  5. Disable the testing UI and protect sensitive operations

    Remove the testing UI from any environment that holds real patient data, or make it reachable only from administrative networks if your team still needs it. Then review the server operations that can delete or expunge data, change configuration or reindex large volumes, and confirm how your release lets you restrict them. Turn off or restrict each one that is not needed for normal clinical use. Confirm the property names and behavior in the documentation for your exact version rather than relying on older examples. Done means the testing UI path returns a not-found or refusal response from outside the administrative network, and a sensitive operation called without the administrative role is refused.

  6. Add authentication and authorization interceptors

    HAPI FHIR does not include a complete security layer, so you add authentication and authorization through its interceptors in front of your identity provider. The sibling topic on authentication and authorization integration covers the rule design, including AuthorizationInterceptor rules, consent and search narrowing. In this step, connect the token validation to your identity provider, then apply the rules agreed for each role. Done means an unauthenticated read of a patient resource is refused, an authenticated request with an allowed scope returns the resource, and a request outside the granted scope is denied. Run these three checks with test accounts that your security team approves.

  7. Enable BALP audit logging

    Turn on Basic Audit Log Patterns (BALP) audit logging so that the server records access to resources as FHIR AuditEvent records. Confirm which interactions the configuration captures, including reads and searches, and where the records are stored and how long they are retained under your policy. Make sure each record identifies the authenticated user or client, which requires the authentication step to be in place first. Done means a read of a test patient resource by a test user produces an audit record that names that user, the resource accessed and the time of access. Check that the record is retrievable by your audit team and that retention is set in writing.

  8. Design partitions if data must be separated

    Use JPA partitioning only if data must be kept apart, for example by tenant, by source system or by region. Each resource is placed in a partition, so decide the partition key and the mapping rules before any clinical data is loaded, because moving resources later is a data project of its own. Confirm how requests are scoped to a partition in your release and how the authorization rules from the previous step apply within each partition. Done means test resources written to two partitions are returned only to requests scoped to their own partition, and a request scoped to one partition cannot read the other. Keep the partition design document with the security configuration.

How hardening differs for WAR, Docker, Kubernetes and air-gapped deployments

With a WAR file, the application server owns most transport and runtime settings, so hardening work sits in the servlet container and the JVM beneath it. TLS is usually terminated by the container connector or by a reverse proxy in front of it. Database and application settings are typically supplied through the container's configuration or environment, which keeps them out of the WAR but makes the platform team responsible for keeping them out of version control as well.

  • TLS: configure the connector or proxy, set a minimum protocol version and approved cipher suites, and document who owns the keystore.
  • Secrets: hold database credentials in the container's secret store or the host environment, out of the WAR and any shared properties file.
  • Testing UI: confirm whether the web testing pages are included in the WAR you deploy, and restrict them at the container or proxy layer if they are.
  • Rotation and logging: rotating a certificate usually means reloading the connector or keystore. Access logs come from the container and application logs from the logging framework, so both need a retention policy.

Confirm the container's supported Java and servlet versions against the HAPI FHIR release you deploy, and check the build options and dependencies against that release's documentation.

Hardening controls for health data on HAPI FHIR

HAPI FHIR does not ship a complete security layer, so hardening is a split of responsibilities across the platform team, the application team and the identity provider. The cards below cover the controls that most often decide whether a health data server is safe to run, and each one names the party that should own it before work starts.

Replace the embedded H2 database

The JPA server starter defaults to an embedded H2 database, which is suitable for trials but not for clinical data. Production deployments use PostgreSQL or Microsoft SQL Server, and MySQL is not supported. Owner: platform team, with the application team confirming schema initialization settings. Check that the database is on a private network segment and is backed up and restored in a tested way.

Keep database credentials out of images

Database usernames and passwords should not be baked into the hapiproject/hapi image or committed to configuration files in source control. Inject them at runtime from the container platform or a secrets manager. Owner: platform team. Check the image history and the Helm values files for any literal credentials before go-live, and confirm rotation procedures with the database team.

Least-privilege database accounts

The application database user should hold only the privileges needed to read and write FHIR resources and run its own schema migrations. Separate the migration account from the runtime account where your change process allows it. Owner: platform team with the database administrators. Ask the upgrade plan to state which account performs schema changes, because this affects permissions during each HAPI FHIR upgrade.

TLS versions and certificates

Terminate TLS at the ingress or application server with currently supported protocol versions and a certificate issued by your internal or public certificate authority. Disable legacy protocol versions and weak cipher suites in the ingress or server configuration. Owner: platform team. Confirm certificate renewal ownership, expiry alerting and how certificates reach the pods without being stored in images.

Restrict the testing UI and operations

The starter can expose a testing web UI and administrative operation endpoints such as those for terminology and bulk operations. Decide which of these reach production at all, and disable or restrict the rest at the gateway or through server configuration. Owner: application team, with the platform team enforcing network restrictions. Verify that restricted paths return denial responses from outside approved networks.

CORS origin allow-lists

CORS support in HAPI FHIR should list only the browser origins that legitimately call the server, rather than allowing all origins. Keep the list short and review it when a new client application is onboarded. Owner: application team. Check that wildcard origins are not enabled in production and that credentialed requests are limited to known front ends.

Secrets handling in Kubernetes

Kubernetes Secrets are base64 encoded rather than encrypted by default, so the platform team should confirm encryption at rest for the cluster datastore and restrict who can read Secret objects. Mount secrets as files or environment values scoped to the HAPI FHIR namespace only. Owner: platform team. Ask how secret rotation triggers a pod restart and how access is logged.

Logs that exclude patient data

Application and access logs should not record request bodies, identifiers or search parameters that contain patient information. Set logging levels for production deliberately and review any custom interceptors for debug output. Owner: application team, with the platform team controlling log routing and retention. Check a sample of logs after a test load to confirm no patient names or identifiers appear.

How to test that the HAPI FHIR server hardening works and fails safely

Verification should prove each hardening control from the outside, and failure testing should show that the server refuses service when a dependency breaks. Start with access. Send requests with no token, and with a token that lacks the required role, to read, write and search endpoints. Each should be refused. From a host outside the intended network, confirm that the testing UI and sensitive operations do not answer. Scan the server's listening ports and confirm that no plaintext HTTP listener accepts connections and that TLS is enforced on every externally reachable path. Then check the running configuration and the database connections in use. The server should be on PostgreSQL or Microsoft SQL Server, with no H2 connection or file active.

Next, test audit and partitions. Make a read and a write as a known test user, then confirm that BALP entries record both events with the user, the resource and the time. Check that the audit store is written, protected from ordinary application users, and kept for the period your policy requires. For partitioning, create resources with the same logical identifier in two partitions, then query from a client scoped to one partition. Test direct reads by ID, searches, includes and references. No resource from the other partition should appear in any response. How partitions map to tenants, regions or data sources is a design decision, so confirm that mapping with your data owners before you write these tests.

Failure testing matters as much as the happy path. For a database outage, stop the database during a write and confirm the server returns an error, does not report success, and leaves no partial data behind. When the database returns, confirm the server recovers without a restart if your deployment promises that. For an expired certificate, let a staging certificate lapse and confirm that clients are refused and the server does not fall back to plaintext. For an identity provider outage, block the provider and confirm that requests are refused rather than served anonymously. In every case, check that error bodies contain no stack traces, connection strings or internal host names. Record the exact status codes and bodies, since they depend on your interceptors and reverse proxy.

Once your own tests pass, commission an independent security test of the deployed server. The testers should be separate from the people who built it, and the scope should cover the FHIR API, the authorization rules, the hosting platform around the server and the administrative paths. Agree the scope, test accounts, environments and rules of engagement in writing before testing starts. DeployOpen provides application and API security testing, cloud and infrastructure testing, and can scope a FHIR-focused engagement with you. Plan a retest after fixes. A security test is not an audit or certification, so ask your compliance lead which independent assessment, and which assessor, your regulators expect.

What drives the effort and cost of HAPI FHIR hardening

This table lists the factors that change how much work HAPI FHIR hardening takes, why each one matters, and how to keep it contained. Read it before asking for a quote, because the same server can take very different effort depending on these inputs. The main takeaway is that scope decisions made early, especially around tenants, interceptors and evidence, usually matter more than the hardening steps themselves.

DriverWhy it changes effort or costHow to keep it down
Calling applications and identity providersEach application and identity provider needs its own token validation, client registration and authorization rules, and each adds test cases.Consolidate clients onto a small set of identity providers and standard scopes, and document the access model before build starts.
Volume and sensitivity of dataHigher sensitivity raises the bar for encryption, access logging, backup testing and breach response. Large volumes lengthen migration and test runs.Classify resource types early, limit which data sets sit in scope for the first release, and agree performance targets in writing.
Number of partitions or tenantsEach partition adds authorization rules, search narrowing checks and isolation tests, since HAPI FHIR does not provide a single security layer.Start with the smallest partition model that meets the requirement, and confirm with the vendor documentation how partitions interact with your chosen interceptors.
Deployment model and number of environmentsEvery environment needs its own configuration, secrets, TLS certificates and database, and changes must be promoted and verified in each one.Use one templated deployment definition (for example, Helm or Docker Compose) across environments and limit production-only settings.
Custom interceptors to write and regression testCustom authorization, consent or audit logic is code that must be written, reviewed and retested after every HAPI FHIR or Java upgrade.Prefer configuration of the built-in interceptors where they meet the requirement, and keep custom code small and well documented.
Integration with existing log and secrets platformsConnecting audit output, metrics and credentials to your SIEM, log pipeline and secrets manager requires mapping, access control and failure testing.Reuse existing collectors and secrets tooling, and confirm log formats and retention with the owning team before design is fixed.
Compliance evidence requirementsAssessors may expect documented configuration baselines, test results, access reviews and audit log samples. Collecting these is labor-intensive if done after the fact.Agree the evidence list with your compliance lead or assessor at scoping, and generate it as part of each test cycle.
Cost components and timingInternal staff time and external services are mostly one-time for the initial hardening. Infrastructure, database hosting or licensing, and ongoing testing recur.Ask the quote to separate one-time work from recurring items, name who pays for each, and state which database and hosting costs are included or excluded.

Questions teams ask before hardening HAPI FHIR themselves or hiring help

Can our own team harden HAPI FHIR without a partner?

Yes, if your team has Java, database, Linux or container, and security engineering skills, plus enough time to own the work after go-live. HAPI FHIR provides building blocks that your team must combine into a security design, including authentication, authorization, TLS, database configuration, audit logging and partitioning. Each choice needs a documented reason tied to your risk. The JPA server starter defaults to an embedded H2 database, so replacing it with PostgreSQL or Microsoft SQL Server is an early decision. In-house efforts most often stall on evidence: test records, configuration baselines and sign-off on the audit design. Ask whether someone will keep these controls current through each HAPI FHIR upgrade.

What does hardening HAPI FHIR cost and what drives it?

DeployOpen does not publish a price list. A quote follows from a written scope. Cost has two parts: one-time work (design, build, configuration, testing, documentation and handover) and recurring work (patching, upgrades, regression testing of custom interceptors, log review and infrastructure). Drivers include the number of resource types and profiles in use, the identity provider you must integrate with, the number of partitions or tenants, the database engine, the number of environments and how much evidence your assessor will expect. Ask each bidder to split the quote into design, build, testing, documentation and handover. Also ask what is excluded, who provides infrastructure and what an ongoing retainer covers.

How long does a HAPI FHIR security hardening project take?

Duration depends on scope and on how quickly your side can move, so request a timeline in the written scope and treat any general figure with caution. Fixed-scope engagements agree deliverables and timelines in writing before work starts. Drivers include the number of environments, the readiness of your identity provider, whether data owners must decide access rules for each resource type, the number of partitions, the maturity of your infrastructure automation and how many review cycles the audit design needs. Delays usually come from waiting for access and decisions more than from configuration itself. Ask for milestones tied to your inputs, a list of dependencies you must meet and the review cycles included.

What must our team provide before hardening work starts?

Plan to provide environments, access, people and decisions. Supply non-production and production-like environments that match your deployment model, with cloud or data center access to build them. Provide identity provider details, including the issuer, client registration, test users and claims mapping. Name data owners who can approve access rules by resource type and partition. Assign a technical owner who can answer questions about the database, network and logging stack. Agree who signs off the audit design and control evidence before build begins, since that sign-off decides what gets documented. Also schedule change windows for TLS certificate changes, database migration and server restarts. Confirm these items in the written scope so gaps show up early.

Does enabling BALP make HAPI FHIR compliant?

No. BALP audit logging records access events, but turning it on does not make a server compliant with any framework. Compliance depends on your controls as a whole: who can access data, how identities are managed, encryption, configuration baselines, backups, monitoring, incident response and vendor management. Your team must document each control, explain how it is implemented in your environment and keep evidence that it operates over time. Independent auditors judge that evidence. DeployOpen prepares systems, controls and evidence for compliance assessments, but it does not issue audit reports, attestations or certifications. Independent auditors and certification bodies do.

Does a Smile CDR support contract change the hardening work?

It can change your support model and who you call when something breaks, but confirm the details with Smile CDR. The HAPI FHIR README points to Smile CDR for commercial support. Hardening still requires design decisions, configuration, testing and evidence in your own environment. Ask Smile CDR which parts of configuration, upgrades, patches and security issues its support covers, and whether that coverage applies to the version you run. Ask whether it covers your custom interceptors as well. Your team still owns the controls it documents, and a support contract does not supply that evidence. Put the responsibilities for each party in the written scope so ownership is clear.

Does DeployOpen issue security or compliance certifications for HAPI FHIR?

No. DeployOpen does not issue certifications, attestations or audit reports. It plans, implements, hardens, documents and supports self-hosted open-source platforms inside your infrastructure, and it prepares systems, controls and evidence for compliance assessments. Independent auditors and certification bodies perform the assessment and issue any report or certificate. Ask the auditor you plan to use which evidence they expect, and raise that list before design starts so the build produces it. DeployOpen can also run security testing of the deployed server and its APIs as a separate scope, which you should specify in writing.

How DeployOpen scopes, hardens and hands over HAPI FHIR servers

DeployOpen plans, implements, hardens, documents and supports self-hosted open-source platforms inside the client's own infrastructure, and HAPI FHIR security hardening follows the same pattern. Work starts from a written, fixed scope, so the database, TLS, interceptor, audit and partitioning decisions are agreed before any configuration changes.

How we scope

  • Confirm the HAPI FHIR version, FHIR release and JDK requirement the server will run on before setting hardening controls
  • Record whether the server runs the JPA starter or a custom build, and which PostgreSQL or SQL Server instance holds the data
  • Agree in writing which operations, the testing UI, BALP audit logging and partitions are in scope, and which are excluded

How we build

  • Replace the default embedded H2 database with a supported production database, then verify schema creation and access rights
  • Configure TLS termination, CORS settings and the testing UI and operations endpoints so they are closed or restricted in production
  • Wire the AuthorizationInterceptor, consent and search narrowing rules, and BALP audit logging to the agreed policy and test each path

How we hand over

  • Deliver the configuration, deployment artifacts and a record of each hardening control mapped to the agreed scope
  • Provide test evidence for access rules, TLS settings, audit events and partition separation, with known gaps listed
  • Document the runbook for upgrades, secret rotation and log review so your operations team can run the server without DeployOpen

How we support

  • Ongoing support, upgrades and continuous testing are available as a retainer that follows the same written scope
  • Re-test hardening controls when HAPI FHIR releases change interceptors, database schema or Java requirements
  • Confirm with the HAPI FHIR project or Smile CDR which commercial support options fit your environment before choosing an approach

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.