A stateless proxy that adds OAuth 2.0 and SMART App Launch authorization to existing FHIR servers.
Quick Start • Features • Architecture • Documentation • Discord
Proxy Smart sits between your SMART apps and FHIR servers, handling authentication and authorization. It doesn't store any clinical data — requests pass through to your existing FHIR servers, and the proxy manages OAuth flows and access control.
| You provide | Proxy Smart handles |
|---|---|
| A FHIR server (HAPI FHIR, Microsoft FHIR Server, AWS HealthLake, etc.) | SMART App Launch 2.2.0 flows |
| Keycloak (included in Docker setup) | OAuth 2.0 authorization & token management |
| Your SMART apps | Scope-based access control & FHIR proxying |
Requirements: Node.js ≥18, Bun ≥1.0, Docker
# Clone the repository
git clone https://github.com/max-health-inc/proxy-smart.git
cd proxy-smart
# Start everything
bun docker:dev
bun install
bun run devThen open:
| Service | URL |
|---|---|
| Admin UI | http://localhost:5173 |
| Backend API | http://localhost:8445 |
| Keycloak | http://localhost:8080 |
No clinical data in the proxy means a smaller attack surface, simpler compliance (HIPAA, GDPR), easy horizontal scaling, and less infrastructure to manage. Audit logging for access patterns and OAuth flows is available when needed.
Full implementation of the SMART App Launch specification — apps that follow the standard work out of the box. OAuth 2.0 with PKCE, JWT validation, scope-based access control, refresh token rotation, and enterprise SSO via SAML 2.0 and OIDC.
Built-in React admin UI for managing SMART apps, FHIR server connections, users, and scopes — no manual config editing required.
Built-in AI assistant with RAG for documentation queries, exposed via an MCP server for programmatic integration with AI tools.
One-command development and production deployments with Docker Compose, including mono-container and multi-container options.
SMART App → Proxy Smart → FHIR Server
↓
Keycloak (OAuth)
graph TB
subgraph Clients
A[Admin UI]
B[SMART Apps]
end
subgraph "Proxy Smart (Bun/Elysia)"
D[FHIR Proxy]
E[OAuth Endpoints]
F[WebSocket]
G[AI Assistant]
end
subgraph Identity
H[Keycloak]
I[(PostgreSQL)]
end
subgraph "FHIR Servers"
K[HAPI FHIR]
L[Other FHIR]
end
A --> D
A --> F
B --> E
B --> D
E --> H
D --> H
H --> I
D --> K
D --> L
G -.-> |OpenAI| X((API))
| Workspace | Description |
|---|---|
backend/ |
Elysia API server, FHIR proxy, OAuth endpoints |
apps/ui/ |
React admin dashboard |
apps/consent-app/ |
Patient consent management UI |
apps/dtr-app/ |
Documentation, Templates & Rules (DTR) app |
apps/patient-portal/ |
International Patient Portal (IPS/IPA) |
apps/smart-dicom-template/ |
Starter kit for imaging AI SMART apps |
shared-ui/ |
Shared React components and utilities |
infra/ |
AWS CDK infrastructure |
| Layer | Technologies |
|---|---|
| Backend | Bun, Elysia, TypeScript |
| Frontend | React 19, Vite, Tailwind CSS |
| Identity | Keycloak + PostgreSQL |
| Testing | Vitest, Playwright |
| Infra | Docker, AWS CDK |
PostgreSQL only stores user/config data. Clinical data stays on your FHIR servers.
Every FHIR proxy request runs through a layered security pipeline:
Request → JWT Validation → Consent + IAL → SMART Scopes → Role-Based Filtering → FHIR Server
| Step | What it does | Default |
|---|---|---|
| JWT Validation | Verifies token signature, expiry, and issuer | Always active |
| Consent + IAL | Enforces patient consent policies and identity assurance level | Configurable |
| SMART Scope Enforcement | Checks the token's scope claim permits the requested resource type and operation (e.g., patient/Observation.read → allow GET on Observation). Supports SMART v1 and v2 scope syntax. |
Enforced |
| Role-Based Filtering | Narrows which data is returned based on fhirUser identity — Patients only see their own data, Practitioners only see assigned patients. |
Enforced |
Each step can be configured independently via environment variables:
| Environment Variable | Options | Default |
|---|---|---|
SCOPE_ENFORCEMENT_MODE |
enforce, audit-only, disabled |
enforce |
ROLE_BASED_FILTERING_MODE |
enforce, audit-only, disabled |
enforce |
enforce— blocks unauthorized requests with HTTP 403audit-only— logs violations but allows the request throughdisabled— skips the check entirely
Proxy Smart inherits Keycloak's proven horizontal scalability. The proxy layer is stateless — it adds no bottleneck on top of Keycloak's auth flows.
Official Keycloak Benchmarks (source)
| Metric | Regularly Tested | Max Tested |
|---|---|---|
| Users | 1,000,000 | 30,000,000 |
| Password logins/sec | 300 | 1,000 |
| Token refreshes/sec | — | 20,000 |
| Client credential grants/sec | — | 2,000 |
CPU Sizing (source)
| Operation | vCPU per unit |
|---|---|
| 15 password logins/sec | 1 vCPU |
| 120 client credential grants/sec | 1 vCPU |
| 120 refresh token requests/sec | 1 vCPU |
Base memory per Keycloak pod: 1,250 MB (includes caches for 10,000 sessions).
6 Pods across 3 AWS availability zones, each with 40 vCPU / 8 GB RAM, backed by Aurora PostgreSQL multi-AZ — achieving 1,000 logins + 20,000 token refreshes per second. CPU usage scales linearly with request count.
# Development (mono container)
bun run docker:dev
# → http://localhost:8445/webapp/
# Production (separate containers)
bun run docker:prod
# → Frontend: http://localhost:5173
# → Backend: http://localhost:8445All Docker commands
| Command | Description |
|---|---|
bun run docker:dev |
Start dev containers |
bun run docker:dev:build |
Build and start |
bun run docker:dev:down |
Stop |
bun run docker:dev:logs |
View logs |
bun run docker:prod |
Start prod containers |
bun run docker:prod:build |
Build and start |
bun run docker:prod:down |
Stop |
bun run docker:prod:logs |
View logs |
bun run docker:backend |
Backend only |
bun run docker:ui |
UI only |
bun run docker:mono |
Monolithic |
Current: v0.0.2-alpha — Working toward SMART App Launch 2.2.0 compliance.
| Milestone | Goal |
|---|---|
| v0.0.5-beta | PKCE, v2 scope syntax, token introspection |
| v0.1.0 | Full SMART 2.2.0 compliance |
| v1.0.0 | Production ready |
See the implementation checklist for details.
| Branch | Purpose |
|---|---|
main |
Production releases (auto-tagged) |
test |
Beta releases (-beta suffix) |
develop |
Alpha releases (-alpha suffix) |
dev/* |
Feature branches (no PR required) |
- Fork the repo
- Create a branch (
dev/your-feature) - Make changes with tests
- Submit PR
See CONTRIBUTING.md for guidelines.
Dual licensed:
- AGPL v3 — open source / non-commercial use
- Commercial license — available for proprietary use
See LICENSE-DUAL.md for details.
- 🤖 AI Assistant (built-in)
- 💬 Discord
- 📖 Documentation
- 🐛 GitHub Issues