This is a submission for the Permit.io Authorization Challenge: API-First Authorization Reimagined
What I Built
I've created MediSecure API Gateway, a specialized data exchange platform for healthcare providers that implements API-first authorization for sensitive medical information.
The platform enables secure, compliant data sharing between healthcare systems while maintaining strict adherence to privacy regulations and patient consent preferences.
In healthcare, data exchange faces unique challenges:
- Strict regulatory requirements (HIPAA, GDPR)
- Complex contextual access needs that change based on purpose of use
- Variable patient consent preferences
- Emergency access scenarios that may override normal restrictions
- Delegation of access between providers
Traditional authorization approaches fail in this environment because they:
- Are tightly coupled to application code
- Cannot adapt to changing contexts without code modifications
- Lack granularity for healthcare's complex access patterns
- Don't provide adequate audit trails for compliance
MediSecure solves these challenges through an API-first authorization approach where:
- Authorization is treated as core API infrastructure, not an application concern
- Access policies are declaratively defined and externalized
- APIs include rich contextual parameters for authorization decisions
- All API endpoints consistently enforce authorization policies
Demo
You can access the demo with these credentials:
Admin credentials:
- username:
admin
- password:
2025DEVChallenge
User credentials:
- username:
newuser
- password:
2025DEVChallenge
The demo showcases:
- API-based access to simulated healthcare records
- Different access scenarios (normal care, emergency, research)
- Patient consent management affecting data access
- Comprehensive audit logs of all authorization decisions
Project Repo
The repository includes:
- A Node.js-based API gateway with Permit.io integration
- Microservices for different healthcare domains (patient records, imaging, prescriptions)
- OpenAPI/Swagger documentation with authorization attributes
- Docker configuration for containerized deployment
- Comprehensive test suite focused on authorization scenarios
My Journey
Building an API-first authorization system for healthcare data changed my perspective on API design and security.
Starting with API Design
Unlike traditional projects where authorization is added to existing endpoints, I started with authorization as a core design principle. Every API endpoint was designed with these considerations:
- What resources are being accessed?
- What context information is needed for authorization decisions?
- How do we handle partial authorization scenarios?
- How will this endpoint behave in emergency access situations?
This "authorization-first" approach led to cleaner, more consistent APIs with better security properties.
The Healthcare Authorization Challenge
Healthcare authorization is particularly challenging because:
- Context determines access - The same user might have different access rights depending on their purpose (treatment, billing, research)
- Patient consent matters - Patient preferences can override organizational permissions
- Emergency scenarios - Standard rules may need to be bypassed in emergencies
- Delegation is common - Providers frequently need to temporarily delegate access
These factors make it impossible to rely on simple role-based access control. My solution was to implement advanced attribute-based access control (ABAC) using Permit.io's policy engine.
Key Implementation Decisions
1. Authorization Context in API Design
I made authorization context explicit in API design:
// Example API endpoint with explicit authorization context
app.get('/api/patients/:patientId/records', (req, res) => {
// Authorization context is explicitly part of the API
const accessPurpose = req.query.purpose || 'treatment';
const emergencyAccess = req.headers['x-emergency-access'] === 'true';
// This context is used in authorization decisions
// ...
});
2. Authorization Middleware for Consistent Enforcement
I implemented API gateway middleware to enforce consistent authorization:
// API gateway authorization middleware
function authorizationMiddleware(req, res, next) {
// Extract resource information from request
const resource = extractResourceFromRequest(req);
// Extract action from HTTP method
const action = mapMethodToAction(req.method);
// Build authorization context
const context = buildAuthContext(req);
// Make authorization decision
permit.check({
user: req.user.id,
action: action,
resource: resource,
context: context
}).then(permitted => {
if (permitted) {
// Authorization successful
next();
} else {
// Authorization failed
res.status(403).json({
error: 'Forbidden',
message: 'You do not have permission to access this resource'
});
}
}).catch(error => {
// Error in authorization
console.error('Authorization error:', error);
res.status(500).json({
error: 'Internal Server Error',
message: 'An error occurred during authorization'
});
});
}
3. Patient Consent Integration
I built a consent management system that feeds into authorization decisions:
// Consent-aware authorization check
async function checkAccessWithConsent(user, patientId, dataCategory, accessPurpose) {
// Get patient consent preferences
const consentPreferences = await getPatientConsentPreferences(patientId);
// Check if consent allows this access purpose for this data category
const consentAllows = consentPreferences.purposes[accessPurpose]?.categories.includes(dataCategory) || false;
// Include consent in authorization context
const authContext = {
patientId: patientId,
dataCategory: dataCategory,
accessPurpose: accessPurpose,
consentStatus: consentAllows ? 'granted' : 'denied'
};
// Make authorization decision
return permit.check({
user: user.id,
action: 'read',
resource: `patient_data:${patientId}:${dataCategory}`,
context: authContext
});
}
Challenges Faced
Challenge 1: Performance at Scale
With thousands of API calls per minute, each requiring detailed authorization checks, performance became a concern. I addressed this through:
- Optimized authorization caching for frequently accessed resources
- Batch authorization checks for listing operations
- Authorization decision prefetching for likely next actions
Challenge 2: Maintaining Consistency Across Microservices
Ensuring consistent authorization across multiple microservices was challenging. My solution was a centralized API gateway that:
- Handles all authorization decisions
- Enriches requests with authorization context before forwarding to services
- Provides a consistent audit trail for all access decisions
Challenge 3: Testing Complex Authorization Scenarios
Testing the myriad permutations of user roles, patient consent, access purposes, and emergency scenarios was daunting. I solved this by developing:
- A specialized authorization testing framework
- Automated test generation for common scenarios
- Policy simulation tools for authorization administrators
Key Learnings
This project transformed my understanding of API-first authorization:
- Authorization belongs in API design, not just implementation
- APIs should communicate authorization context explicitly
- Consistent patterns improve both security and developer experience
- Externalized authorization dramatically improves flexibility and compliance
- Policy-as-code enables version control and testing of authorization rules
API-First Authorization
I implemented several innovative authorization patterns using Permit.io:
Declarative Resource Definitions
I defined healthcare resources with rich attributes for authorization:
// Define patient record resource
await permit.api.resources.create({
key: "patient_record",
name: "Patient Medical Record",
description: "Electronic health record for a patient",
actions: {
"read": { name: "Read Record" },
"update": { name: "Update Record" },
"delete": { name: "Delete Record" },
"share": { name: "Share Record" }
},
attributes: {
"record_type": {
type: "string",
enum: ["demographics", "medications", "lab_results", "imaging", "notes", "billing"]
},
"sensitivity": {
type: "string",
enum: ["normal", "sensitive", "restricted"]
},
"department": { type: "string" },
"attending_physician": { type: "string" }
}
});
Policy-as-Code Implementation
I implemented healthcare authorization policies as code:
// Create policy for patient record access
await permit.api.policies.create({
key: "patient_record_access",
resource: "patient_record",
actions: ["read"],
effect: "allow",
conditions: [
// Treating physicians always have access
`resource.attending_physician == user.id`,
// Department-based access for normal sensitivity
`resource.sensitivity == "normal" && resource.department == user.department`,
// Emergency access override
`context.emergency_access == true && user.role == "physician"`,
// Consent-based research access
`context.access_purpose == "research" &&
context.consent_status == "granted" &&
user.role == "researcher"`
]
});
API Gateway Integration
I integrated Permit.io at the API gateway level:
// API Gateway route with integrated authorization
apiGateway.route({
method: 'GET',
path: '/api/patients/:patientId/records/:recordType',
preHandlers: [
// Authentication middleware
authenticate,
// Authorization middleware
async (req, res, next) => {
try {
// Extract resource information
const patientId = req.params.patientId;
const recordType = req.params.recordType;
// Build rich authorization context
const context = {
access_purpose: req.query.purpose || 'treatment',
emergency_access: req.headers['x-emergency-access'] === 'true',
access_time: new Date().toISOString(),
consent_status: await getConsentStatus(patientId, recordType, req.query.purpose)
};
// Check permission
const permitted = await permit.check({
user: req.user.id,
action: 'read',
resource: `patient_record:${patientId}:${recordType}`,
context: context
});
if (!permitted) {
return res.status(403).json({
error: 'Forbidden',
message: 'Not authorized to access this patient record'
});
}
// Log access for audit
await logAccess({
user: req.user.id,
resource: `patient_record:${patientId}:${recordType}`,
action: 'read',
context: context,
timestamp: new Date(),
status: 'permitted'
});
next();
} catch (error) {
console.error('Authorization error:', error);
res.status(500).json({
error: 'Internal Server Error',
message: 'Error during authorization check'
});
}
}
],
// Forward to appropriate microservice
target: 'http://patient-records-service/records'
});
Authorization-Aware API Documentation
I enhanced OpenAPI documentation with authorization attributes:
paths:
/patients/{patientId}/records/{recordType}:
get:
summary: Get patient record by type
parameters:
- name: patientId
in: path
required: true
schema:
type: string
- name: recordType
in: path
required: true
schema:
type: string
enum: [demographics, medications, lab_results, imaging, notes, billing]
- name: purpose
in: query
description: Purpose of access (authorization context)
schema:
type: string
enum: [treatment, payment, research]
default: treatment
security:
- BearerAuth: []
x-authorization:
resource: patient_record
action: read
contextParams:
- name: purpose
in: query
- name: emergency_access
in: header
responses:
'200':
description: Patient record retrieved successfully
'403':
description: Not authorized to access this record
Policy Testing Framework
I built a comprehensive testing framework for authorization policies:
// Authorization policy test
test('Physician can access patient records in emergency', async () => {
// Setup user
const physicianUser = {
id: 'dr-smith',
attributes: {
role: 'physician',
department: 'cardiology'
}
};
// Setup resource
const patientRecord = {
id: 'patient-123-cardiology',
attributes: {
record_type: 'notes',
sensitivity: 'restricted',
department: 'neurology', // Different department
attending_physician: 'dr-jones' // Different physician
}
};
// Test normal access (should fail)
const normalAccess = await testPolicyDecision({
user: physicianUser,
action: 'read',
resource: patientRecord,
context: {
access_purpose: 'treatment',
emergency_access: false,
consent_status: 'not_required'
}
});
expect(normalAccess.decision).toBe('deny');
// Test emergency access (should succeed)
const emergencyAccess = await testPolicyDecision({
user: physicianUser,
action: 'read',
resource: patientRecord,
context: {
access_purpose: 'treatment',
emergency_access: true,
consent_status: 'not_required'
}
});
expect(emergencyAccess.decision).toBe('allow');
});
By implementing API-first authorization with Permit.io, I was able to create a healthcare data exchange platform that maintains strong security and compliance while providing the flexibility needed for real-world healthcare scenarios.