Healthcare
The challenge
Cross-jurisdictional health data sharing is one of the hardest authorization problems in any sector:
- Each jurisdiction has its own rules — a physician in one province needs a patient record from another, but each jurisdiction enforces different privacy regulations and consent requirements.
- No federated authorization model — sharing today means VPNs, fax machines, or custom point-to-point integrations per partner. Every new connection is a months-long project.
- Consent is a checkbox, not a policy — patient consent is captured in a database but not enforced programmatically at the authorization layer. Compliance depends on application logic, not infrastructure.
- Audit is reconstructed, not built in — demonstrating compliance means stitching together logs from multiple systems after the fact. Regulators want to see who accessed what, when, and under what authority.
- New actors have no model — AI agents, remote monitoring systems, and cross-institutional research tools need access but have no authorization framework in the existing infrastructure.
How PBAC handles it
Federated identity, local policy control
Each jurisdiction keeps its own identity provider and defines its own authorization rules. PBAC federates the access decisions — so a provider authenticated by Province A's IdP can access a patient record in Province B, governed by Province B's policies.
Consent as a policy obligation
Patient consent is not a static flag — it is enforced as a policy-driven obligation at the moment of access. When a provider requests a health record, OPA evaluates whether consent exists, whether it covers the requested scope, and whether the clinical context qualifies. Consent can trigger step-up verification or redaction of sensitive categories.
Scoped access by clinical context
Resource types (HealthRecord, Prescription, LabResult, Encounter) are defined with fine-grained scopes. A pharmacy system gets prescription.read and prescription.dispense — not access to the full health record. Policy enforcement happens at the token layer, not in each application.
Every decision logged
Every access decision — allowed, denied, or constrained — is logged with the subject, the resource, the action, the policy that governed it, and any obligations returned. Compliance audit is a query, not a reconstruction project.
Architecture
Resource types and scopes
| Resource | Type URI | Scopes |
|---|---|---|
| HealthRecord | urn:health:health-record | read, write, share |
| Appointment | urn:health:appointment | read, write, cancel |
| Prescription | urn:health:prescription | read, dispense |
| LabResult | urn:health:lab-result | read, write |
| Encounter | urn:health:encounter | read, write |
Scope-resource binding: Scopes are grouped under resource types in granted_resources. read and write for HealthRecord are in the grant for urn:health:health-record. No cross-resource leakage.
Resource servers
| RS | Resource Indicator | Types Served |
|---|---|---|
| EHR API | https://api.health.example.com/ehr/* | HealthRecord, Encounter |
| Hospital API | https://api.health.example.com/hospital/* | Appointment, Encounter |
| Pharmacy API | https://api.health.example.com/pharmacy/* | Prescription |
| Lab API | https://api.health.example.com/lab/* | LabResult |
Trust issuers
- https://trust.example.com — Primary trust framework
- https://federation.health.org — Health federation (providers, pharmacies, labs)
Client apps and entitlements
| App | Type | granted_resources |
|---|---|---|
| Patient Portal | confidential_app | urn:as:userinfo (openid); health-record, appointment with scopes; resource_indicators for ehr/, hospital/ |
| Provider EHR | confidential_app | urn:as:userinfo (openid); health-record, encounter, lab-result with scopes; resource_indicators for ehr/, lab/ |
| Pharmacy System | confidential_app | urn:as:userinfo (openid); prescription: read, dispense; resource_indicator for pharmacy/* |
| Lab Viewer | confidential_app | urn:as:userinfo (openid); lab-result: read; resource_indicator for lab/* |
Key flows:
- Patient Portal: health-record.read, appointment.read/write
- Provider EHR: health-record.read/write, encounter.read/write, lab-result.read
- Pharmacy: prescription.read, prescription.dispense
- Lab Viewer: lab-result.read only
Example token requests
Patient Portal — read health record:
scope=openid read
resource=https://api.health.example.com/ehr/records
resource_types=urn:health:health-record
Provider EHR — write encounter:
scope=openid read write
resource=https://api.health.example.com/ehr/encounters
resource_types=urn:health:encounter
Pharmacy — dispense prescription:
scope=openid read dispense
resource=https://api.health.example.com/pharmacy/prescriptions
resource_types=urn:health:prescription
Policy implementation note
The token policy uses the unified model: granted_resources (array of { type, scopes, resource_indicator? }). Resource-scoped scopes require resource_types in the request. Policy evaluates via oauth.entitlements.client_is_allowed.
Try it
See this model in action with the Quickstart — from credentials to a policy decision in 5 minutes.
Want to discuss how PBAC fits your environment? Talk to us →
Next steps
- Quickstart — From credentials to a policy decision in 5 minutes
- Consent Extension — Implement consent-as-obligation for user-delegated flows
- Token exchange — Cross-domain identity via id_token exchange for federated access