This application provides a reference for using Oso Cloud's local authorization to create a multi-tenant electronic medical record (EMR) application with a microservice architecture.
The application includes a multi-tenant-enabled user management system, which lets you create organizations (tenants), as well as users within those tenants with specific roles. When running the app, you have a super-admin like impersonation privilege that lets you view the application state as any given user.
The main purpose of the application is to demonstrate Oso's ability to handle electronic medical records.
The EMR application focuses on two objects:
- Appointments between medical staff and patients
- Records created as a result of those appointments. Records have two
components:
- Public notes meant to be widely visible
- Internal notes meant only for other medical staff
Electronic medical records are notoriously complex, which the application model mirrors. To help develop a sense of what the application does, we'll focus on which roles a user can have on an organization and what that entitles them to do.
The root
user that you can access when you launch the app is a special global
admin
user that can create organizations, as well as other read-oriented
capabilities. In this application, only the root
user in the _root
organization is an admin
.
- Create users within their organization
- Schedule appointments
- View all appointments
- Cancel appointments
- View the public notes of any record within their organization
- View any appointments for which they are the patient
- View the public notes of any record originating from an appointment for which they are the patient
- View all appointments
- Complete appointments for which they are the medical staff
- Create records for appointments for which they are the medical staff
- View the public notes of any record within their organization
- View the internal notes of any record:
- Originating from an appointment for which they are the medical staff
- For any appointment whose patient has an appointment with this user, as
long as that state is not
canceled
.
- Oso Cloud w/ both centralized and local authorization
- Docker Compose
- Next.js with React server components for the backend
- PostgreSQL
The project contains many reference files, which provide realistic examples of how to accomplish complex tasks in your own application.
File | Description |
---|---|
oso_policy.polar |
A complex policy demonstrating RBAC, ReBAC, ABAC, and field-level access |
oso_local_auth*.yml |
Per-serivce local auth configuration |
actions/*.ts |
Node.js SDK authorization enforcement w/ React server components. For more details, see Enforcement patterns |
app/**/*.tsx |
React frontend integrating with authorization-oriented backend |
lib/oso.ts |
Oso client generation/config |
Different components offer different examples of authorization patterns:
Component | File | Pattern |
---|---|---|
Organization (tenants) |
/actions/org.ts |
RBAC: multi-tenancy, global roles |
User within Organization |
/actions/user.ts |
ReBAC: user-resource relations |
Appointment , Record |
/actions/emr.ts |
ReBAC: user-resource relations, Field-level |
To manage authorization data, Oso offers a service to sync data to Oso's centralized authorization data. However, the syncing service is only available to customers at the Growth tier or above.
We've included details for using the sync service for documentation purposes, but commented out places where it would run.
env_template_oso_sync.yml
Dockerfile.oso_reconcile
docker-compose.yml
The physical application that gets built via Docker compose is:
- Next.js with React server components for the backend
- PostgreSQL
The React server components that constitute the backend authorize requests using Oso Cloud using local authorization.
However, the logical application that gets built mimics a microservice architecture, primarily enforced by creating distinct databases for each service. In the case of this application, the two services are:
- User management, which creates organizations and users
- EMR, which lets users mange appointments and records
The backend, though physically unified, behaves as if it is not and uses separate clients to connect to both the PG database and Oso Cloud.
In this diagram, the lines connecting the backend services represent distinct clients.
next.js
┌────────────────┬───────────────────┐
│ frontend │ backend │ PG DB
│ │┌─────────┐ │ ┌─────────┐
│ ││ /users ┼────────┼───► Users │
│ │└──▲──────┘ │ │ │
│ │ │┌─────────┐ │ ├─────────┤
│ │ ││ /emr ┼────┼───► EMR │
│ │ │└────────▲┘ │ └─────────┘
└────────────────┴───┼─────────┼─────┘
│ │
┌▼─────────▼──┐
│ Oso Cloud │
└─────────────┘
With a microservice architecture like the one laid out above, services do not
have access to each others' data. This means that even though authorization
decisions made in many services will depend on the /users
service, they cannot
access it directly.
To handle this complexity, Oso offers centralized authorization
data. In this
application, it means that as the /users
service performs CRUD operations on
its database, it also needs to propagate those changes to Oso Cloud. This way,
when the /emr
service needs to enforce authorization, it can do so with the
copy of the /users
data that Oso Cloud has.
Further, because Oso's local authorization considers centralized authorization
data when generating SQL expressions, the /emr
service can still use local
authorization.
-
Create an API key for the application. Make sure you save this!
-
Copy
/oso-policy.polar
as the policy in the environment by deploying it. -
Convert
.env.example
to.env
with the appropriate values set, e.g.OSO_CLOUD_API_KEY
. -
Install the dependencies using a Node.JS package manager, such as
npm
oryarn
. -
Run the app locally via:
docker compose up --build
Note the provided
docker-compose.yml
file makes the PostgreSQL container accessible from the host machine on port5433
. This should reduce the likelihood of interfering with any local PostgresSQL instances. Within Docker compose network, it still runs on the standard port,5432
.If that port fails to work, grep for it in the provided code and change it to any other value.
-
Load the app at
http://localhost:3000
From here you can create and manage:
Organization
sUser
sAppointment
sRecord
s
TODO: Add a style to the app. Currently, the GUI is entirely unstyled HTML.