Skip to main content

Access Controls

Introduction

This document describes the core concepts of Medplum Access Controls. Security and access controls are notoriously difficult. Complex business and regulatory requirements often lead to a mess of incomprehensible rules. Medplum strives to create a simple and understandable model, which is flexible enough to handle all unique security needs.

Core Model

Medplum is built on FHIR, an international standard for healthcare interoperability. FHIR includes standard definitions for almost every imaginable healthcare concept.

One of the central concepts of FHIR is the "Resource". Everything is a resource: patients, practitioners, observations, medications, and many more. Every resource has a "Resource Type". There are more than 100 standard resource types.

All resources exist within a "Project". A project is a top-level container. In general, each healthcare organization will have one project for all of their resources. If you are self-hosting Medplum, then you probably only need one project. Importantly, projects are mutually exclusive. For example, a "Patient" resource can only be in one "Project". If you need to represent the same patient in multiple projects, you need to create a copy.

All resources can be tagged with one or more "Compartments". A compartment is simply a group of resources. Importantly, compartments are not mutually exclusive. A resource can (and often will) exist in multiple compartments.

For example, consider an "Observation" resource representing a blood pressure measurement. That Observation resource will fall into the following Compartments:

  • "Patient" - for the "subject" of the observation
  • "Practitioner" - for the "performer" of the observation
  • "Encounter" - for the "encounter" of the observation

Resources are automatically assigned to compartments based on rules. The FHIR standard includes definitions for standard compartments such as "Patient", "Practitioner", and "Encounter". Developers can create custom compartments using the "CompartmentDefinition" resource.

Now that we have defined "Resource", "Resource Type", "Project", and "Compartment", we can discuss how they relate to security and access controls.

Every user account can have one or more "Project Memberships". A project membership represents access to resources within a project. The user can either be granted access to all resources within the project, or limited access to a set of compartments.

Access Policies

Users within a Project can be assigned Access Policies. Access Policies are an advanced method of restricting access to certain resource types or even certain fields within a resource type.

Access policies allow you to:

  • Block access to any resource type
  • Grant read only access to any resource type
  • Grant read/write access to any resource type
  • Grant read only access to any property
  • Grant read/write access to any property

Access policies also allow you to grant access by "Compartment".

Example: Resource Type

The following access policy grants read/write access to the "Patient" resource type:

{
"resourceType": "AccessPolicy",
"name": "Patient Example",
"resource": [
{
"resourceType": "Patient"
}
]
}

Example: Read-only Resource Type

The following access policy grants read-only access to the "Patient" resource type:

{
"resourceType": "AccessPolicy",
"name": "Patient Example",
"resource": [
{
"resourceType": "Patient",
"readonly": true
}
]
}

Example: Hidden fields

The following access policy grants read-only access to the "Patient" resource type, but hides "name" and "address":

{
"resourceType": "AccessPolicy",
"name": "Patient Example",
"resource": [
{
"resourceType": "Patient",
"readonly": true,
"hiddenFields": [
"name",
"address"
]
}
]
}

Example: Healthcare Partnerships

A common need is to grant access to a subset of resources for a healthcare partnership. For example, a lab provider may want to grant access to all patient records that originated from a specific lab customer.

This can be achieved using Access Policy compartments.

Assume that we have an Organization resource representing the customer:

{
"resourceType": "Organization",
"name": "Example Customer Organization",
"id": "a23a2966-d58a-4098-b41b-e8f18bcda339"
}

This access policy grants read-only access to all Patients that are within that customer's "account" compartment:

{
"resourceType": "AccessPolicy",
"name": "Patient Example",
"compartment": {
"reference": "Organization/a23a2966-d58a-4098-b41b-e8f18bcda339",
"display": "Example Customer Organization"
},
"resource": [
{
"resourceType": "Patient",
"readonly": true,
"compartment": {
"reference": "Organization/a23a2966-d58a-4098-b41b-e8f18bcda339",
"display": "Example Customer Organization"
}
}
]
}

When a user has such an Access Policy, the following happens:

  • Any resource created or updated will be tagged with meta.account set to Organization/a23a2966-d58a-4098-b41b-e8f18bcda339
  • Any read or search operation will filter on meta.account equals Organization/a23a2966-d58a-4098-b41b-e8f18bcda339

The meta.account property is not FHIR standard. It is an extra Reference property in the Meta section.

For example:

{
"resourceType": "Patient",
"id": "54aa8595-e3a7-48ae-af91-9c7cb940149b",
"meta": {
"versionId": "02900c57-4da8-498f-85d5-5077077e3e2c",
"lastUpdated": "2022-01-13T16:21:11.870Z",
"account": {
"reference": "Organization/a23a2966-d58a-4098-b41b-e8f18bcda339",
"display": "Example Customer Organization"
}
},
"name": [
{
"given": [
"Homer"
],
"family": "Simpson"
}
]
}

Because the account-tagging is handled within the resource, project administrators and API users can set the account directly.