March 1st, 2022

Privacy in Medical Systems using FHIR

Introduction

FHIR (Fast Healthcare Interoperability Resources) specifications are becoming a standard in medical systems, allowing interoperability and data exchange based on a known model, accelerated by cloud providers’ offerings of datastore, APIs, and solutions based on FHIR capabilities.

In its native form, FHIR implementations are un-opinionated regarding row-level authorization, such as ownership of records. However, the reality is that medical systems have vital requirements around data governance, ownership, and access controls to specific records in the store.

The FHIR spec does define RBAC and ABAC (Role/Attribute Based Access Controls) as models which can be used to authorize requests by roles, ownership, or even delegation of access (using the Consent resource type). Still, known server and client platforms that implement FHIR such as Azure Healthcare API, Google Healthcare API, Firely, HAPI, etc. do not offer this functionality out of the box.

Our Microsoft Commercial Software Engineering team focuses on healthcare industry solutions, working directly with our customers’ development teams to build their next-generation platforms, leveraging different cloud and open-source technologies. We see a recurring pattern from our engagements designing data privacy regulations and authorizations when accessing FHIR data. There is much complexity in asking who a resource belongs to and who can access it for reading or writing. There will usually be a different answer based on the applicative implementation using FHIR. For instance, in a medical institution, records in the FHIR datastore could be owned by the practitioner who uploads them, while in a consumer-based medical records store, the patients may own their records and they delegate access to them.

This post aims to describe how our team leveraged FHIR specification to define a model of ownership for resources and delegation of access to FHIR resources by their owners.

Challenges and Objectives

Customers may encounter a more refined level of authorization in scenarios where the datastore contains data belonging to different parties, such as multi-tenant. Implementing multi-tenancy usually will take one of the following approaches:

  • separate database
  • separate schema
  • shared schema

In the typical case of a multi-tenant store, there should be no access for one tenant to another’s data. In such cases either a separate database or separate schema can be used. A shared schema may not have the isolation boundaries that the other patterns do. Still, it is the most straightforward design and work-with once the model allows for applying filtering on the data based on the request’s identity. A user who belongs to tenant A can only Create, Read, Update or Delete (CRUD) for resources associated with the same tenant. This pattern is also the best fit for scenarios where multiple tenant queries are required or where data owners can share data from one tenant with users of other tenants.

Private medical store

Defining multi-tenancy in FHIR terminology, tenants are FHIR entity-resources such as Practitioner, Patient, or Organization. Other FHIR resources are either “owned” by them and can be only CRUD by them or require delegation of access rights to them by their owner to the requester.

A privacy-preserving FHIR middleware acts as a reverse proxy between the request origin and the FHIR datastore to perform the required filtering based on the user accessing the system. For more information on using a reverse proxy to perform such actions on top of FHIR specifications, visit Microsoft’s Health Architectures and specifically the FHIR proxy description.

The next section will define the ownership models of resources in a system where patients own their records. Next, it describes how a practitioner can read patients’ records using their owners’ delegation of access to resources.

Ownership Model Description

Level 4 FHIR resources such as Observation or Immunization are used for record-keeping and data exchange. They will typically reference Level 3 FHIR resources, which link to real-world concepts in the healthcare system such as Patient or Practitioner. Additionally, Level 2 FHIR resources such as Consent are used for supporting the implementation with cross-cutting concerns such as security, privacy, auditing, conformance, etc.

To build ownership-based authorization, so that only owners of documents can retrieve their records, we inspect every request going through the reverse proxy to determine the owner of the resources which are input or output. If the request is made by the resource owner, it will follow through with the operation, else it will return a forbidden error.

The following swim-lane diagrams explain the process to authorize a request on behalf of a resource owner:

Image PrivacyFhir Swimlane1

 

 

  • User (or service on behalf of the user) initiates the request for a resource.
  • Authorization server controls authorization of users and services such as in the case of the FHIR client authenticating to the FHIR datastore.
  • FHIR Proxy (Controller), FHIR Proxy (Privacy Middleware) and FHIR Proxy (FHIR Client) are logical layers of the reverse proxy between the user and the FHIR datastore.
    • FHIR Proxy (Controller) is the controller layer.
    • FHIR Proxy (Privacy Middleware) implements the authorization logic.
    • FHIR Proxy (FHIR client) is an open source FHIR implementation such as Firely.
  • FHIR Datastore holds the data in FHIR format, for instance a FHIR API for Azure.
  • Note that the diagram flows through a GET request and the authorization is done post-process (after calling the FHIR datastore). In the case an update request, checking for the authorization at Privacy FHIR client is done pre-process.

When performing a GET request for a single FHIR observation record:

https://contosofhir.azurehealthcareapis.com/Observation/f001

The response looks like this (source):

{
  "resourceType": "Observation",
  "id": "f001"
  "text": {...},
  "identifier": [...],
  "status": "final",
  "code": {...},
  "subject": {
    "reference": "Patient/f001",
    "display": "James Chalmers"
  },
  "effectivePeriod": {...},
  "issued": "2013-04-03T15:30:10+01:00",
  "performer": [
    {
      "reference": "Practitioner/f005",
      "display": "A. Langeveld"
    }
  ],
  "valueQuantity": {...},
  "interpretation": [...],
  "referenceRange": [...]
}

Notice the “subject” field which that is populated by a reference to a Level 2 FHIR resource. The patient James Chalmers should be the only one who can retrieve this document.

Requesting the patient details from the FHIR datastore:

https://contosofhir.azurehealthcareapis.com/Patient/f001

Returns the following response:

{
  "resourceType": "Patient",
  "id": "f001",
  "text": {...},
  "identifier": [
  {
    "system":"https://contoso.b2clogin.com",
    "value":"cbcd0705-49f0-41ad-af71-c4599783842f"
  }
  ]
  "active": true,
  "name": [
    {
      "use": "official",
      "family": "Chalmers",
      "given": [
        "James"
      ]
    }
  ],
  "telecom": [...],
  "gender": "male",
  "birthDate": "1974-12-25",
  "deceasedBoolean": false,
  "address": [...],
  "contact": [...],
  "managingOrganization": {
    "reference": "Organization/1"
  }
}

Note how using identifier attribute for the patient in the response above indicates the record of their identity in our identity management system.

Linking this back to the authentication process which precedes the request to the API, the assumption is that the authorization header is populated with a bearer token JWT that has the same user identifier (sub claim) and system identifier (iss claim):

{
  "sub": "cbcd0705-49f0-41ad-af71-c4599783842f",
  "name": "James Chalmers",
  "iat": 1516239022,
  "iss": "https://contoso.b2clogin.com"
  "role": "Owner"
}

Role claim is used to determine if the user’s FHIR record should be read from the resource type used to store owners (Patients in our case).

Access Delegation Model Description

Modeling access delegation by owners (patients) to readers (practitioners, organizations) uses a FHIR Consent resource, which the patient creates in the same manner described above. A single consent document may refer to several resources and several actors (readers) to which it applies.

The following swim-lane diagrams explain the process to authorize a request on behalf of a resource reader:

Image PrivacyFhir Swimlane2

A sample consent record which James Chalmers, our patient, created, allows access to a practitioner whose ID is f001 access to the observation record Observation/f001. Note the data, provision.actor and patient fields that reference the resources mentioned above:

{
  "resourceType": "Consent",
  "id": "f001",
  "text": {...},
  "status": "active",
  "scope": {
    "coding": [
      {
        "system": "http://terminology.hl7.org/CodeSystem/consentscope",
        "code": "patient-privacy"
      }
    ]
  },
  "category": [
    {
      "coding": [
        {
          "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
          "code": "INFAO"
        }
      ]
    }
  ],
  "patient": {
    "reference": "Patient/f001",
    "display": "James Chalmers"
  },
  "dateTime": "2015-11-18",
  "organization": [...],
  "sourceAttachment": {...},
  "policyRule": {
    "coding": [
      {
        "system": "http://terminology.hl7.org/CodeSystem/v3-ActCode",
        "code": "OPTOUT"
      }
    ]
  },
  "provision": {
    "actor": [
      {
        "role": {
          "coding": [
            {
              "system": "http://terminology.hl7.org/CodeSystem/v3-ParticipationType",
              "code": "CST"
            }
          ]
        },
        "reference": {
          "reference": "Practitioner/f001"
        }
      },
      {
        "role": {
          "coding": [
            {
              "system": "http://terminology.hl7.org/CodeSystem/v3-ParticipationType",
              "code": "PRCP"
            }
          ]
        }
    ],
    "action": [
      {
        "coding": [
          {
            "system": "http://terminology.hl7.org/CodeSystem/consentaction",
            "code": "access"
          }
        ]
      }
    ],
    "data": [ 
    {
       "meaning": "instance",
       "reference": {
          "reference": "Observation/f001"
       }
    }
    ]
  }
}

The referenced practitioner’s record:

{
  "resourceType": "Practitioner",
  "id": "f001",
  "text": {...},
  "identifier": [
  {
     "system":"https://contoso.b2clogin.com",
     "value":"ascd28u4-22d0-hjd9-jd83-c4sgf235123s"
  }
  ]
  "active": true,
  "name": [
    {
      "family": "Careful",
      "given": [
        "Adam"
      ],
      "prefix": [
        "Dr"
      ]
    }
  ],
  "address": [...],
  "qualification": [...]
}

Linking them to the user who’s authorization header is a JWT with the same sub and iss claims:

{
  "sub": "ascd28u4-22d0-hjd9-jd83-c4sgf235123s",
  "name": "Adam Careful",
  "iat": 1516239022,
  "iss": "https://contoso.b2clogin.com"
  "role": "Reader"
}

When the Adam Careful, the practitioner queries for Observation/f001 using the same URL as the patient did, the FHIR proxy, aware of his “reader” role, first queries the FHIR datastore for consents with the following attributes:

  • The practitioner is listed as a performer
  • The queried observation is listed as a data record
  • The consent status is active
  • The time of request is bound by the the consent’s period
  • Advanced scenarios such as write-access by non-owners may also query for other consent fields such as consent’s action type or scope.

If a consent was found, the actual document is queried from the FHIR datastore and returned to the user with a reader role.

Implementation Concepts

This section provides a high level description of our implementation for the authorization at the private FHIR proxy layer.

We use the standard FHIR SDKs for dotnet, Firely, for both modeling of FHIR types at the application layer and for REST interface with the FHIR datastore at the lower levels, which is where the authorization is applied. Our goal in designing the authorization middleware is to encapsulate the known SDK’s REST client API, and to provide the rest of the application the same API surface, composing the user’s identity on top of it.

Here is sample of the firely SDK’s API used for REST protocol with the FHIR datastore, BaseFhirClient.cs (source):

https://gist.github.com/balteravishay/ff93a071ec869fa1f901b560ed98da60

 

This is a composing IAuthorizedFhirService, which offers similar interface to the one above, adding the User’s model structure as a parameter to the methods.

https://gist.github.com/balteravishay/d3a569c10a44e4b0b044c5a2d3873225

 

The rest of the application code uses only IAuthorizedFhirService interface for making requests to the FHIR datastore. An example is seen in the code below, taken from a sample controller for the Patient resource, creating a new Patient Record.

https://gist.github.com/balteravishay/6f91a37a23cbd29673cfe41aa74c09c2

 

Internally, the implementation of IAuthorizedFhirService uses a an authorization middleware, as seen in the following code snippet that shows how a resource is first authorized before created in the datastore during a Create method.

https://gist.github.com/balteravishay/f3d8630345207843be47b24be63317c1

 

The authorization middleware has a single method, AuthorizeAsync, as seen above, encapsulating the invocation of different authorization policies based on the user’s role, generalized by the interface IAccessByRole.

This is an IAccessByRole implementing code validating a reader’s access to a resource by searching the datastore for a consent specific to the user over the resource.

https://gist.github.com/balteravishay/1c99a1cf9d478e10b046add66e6f35e3

 

Validating an owner’s access to resources by a different implementation for IAccessByRole, is performed by reading the ownership (subject) property of the resource and matching it to the user’s identification.

https://gist.github.com/balteravishay/93c7d7e3e4b212d0a837d7bac8d63760

 

Limitations of the current implementation

FHIR spec coverage: FHIR spec covers many resource types, where not all resource types define the same ownership properties. For instance, an Observation refers to the Patient by subject field, while Consent refers to the Patient by the patient field.

FHIR defines Compartments as well as FiveWs as abstractions over FHIR resources that can be helpful for such exploration of the model, however, these are not currently returned by SDK.

Additionally, the current implementation supports JSON only, but can be modified easily to further support XML and Turtle.

Reduced Performance: Given the additional requests from the proxy to the datastore to determine the autorization of every resource for the requesting user, there is an expected hit to performance. GET/Search API verbs are expected to have the greatest impact, as they return a set of resources, each having to to be validated by the proxy. To optimize the execution of such methods, a caching mechanism can be used to reduce the number of requests to the FHIR server.

Conclusion

This post covered the model that our team worked by with customers, as we build secure FHIR based applications that offer authorization and access management down to the row-level, while maintaining native FHIR specification protocol.

As we continue our work to support more FHIR resource types and as we explore advanced capabilities of FHIR which allow validation and abstractions, we expect to release more artifacts which we hope offer other teams and the FHIR community a good reference for making such capabilities available in their products.

To get started, check out the coming releases of Firely SDK where our team contributed the implementation of FiveWs pattern to enable other teams with building such models, and the secure Fhir Proxy repository which is maintained by the Microsoft Health group showcasing authorization and RBAC over FHIR data stores.

Acknowledgements

Contributors to the solution from the Microsoft team listed in alphabetical order by last name: Sharon Hart, Nava Vaisman Levy, Shrian Rubin Manaev, Itye Richter.

0 comments

Discussion are closed.