Medplum is a comprehensive FHIR-compliant healthcare data platform that provides secure data management, access control, and interoperability capabilities. The DHTI integration includes:
- Medplum Server: FHIR-compliant healthcare data backend
- Medplum App: Web-based user interface for data management
- mpclient: OAuth2 proxy for FHIR API access with token management
- Supporting Services: PostgreSQL database and Redis cache
dhti-cli compose add -m medplum
dhti-cli docker -uThis will add and configure all Medplum services with their dependencies.
| Service | Port | URL | Purpose |
|---|---|---|---|
| medplum-server | 8103 | http://localhost:8103/ |
FHIR API server, OAuth2 endpoints, admin API |
| medplum-app | 3103 | http://localhost:3103/ |
Web UI for data management and administration |
| mpclient | 8111 | http://localhost:8111/ |
OAuth2 proxy for FHIR API access with token management |
| postgres-db | 5432 | (internal) | Primary database for Medplum data |
| redis | 6379 | (internal) | Caching and session management |
- Create an account at
http://localhost:3103/to access the Medplum App. - Create a project
- Add an client application to obtain
MEDPLUM_CLIENT_IDandMEDPLUM_CLIENT_SECRETfor mpclient configuration. - Update mpclient configuration ~/dhti/docker-compose.yml` and set the client ID and secret. Restart the mpclient service.
- Login at
http://localhost:8111/using the "Login with Medplum" button to authenticate via OAuth2. - proxy FHIR API requests through mpclient at
http://localhost:8111/fhir/R4/
The core backend service providing:
- FHIR R4 API: Full FHIR R4 resource management
- OAuth2 Server: Authentication and authorization
- RESTful Endpoints:
/fhir/R4/*- FHIR resource operations/oauth2/authorize- OAuth2 authorization endpoint/oauth2/token- Token exchange endpoint/healthcheck- Service health status
Key Configuration:
MEDPLUM_PORT: 8103
MEDPLUM_BASE_URL: 'http://localhost:8103/'
MEDPLUM_DATABASE_HOST: 'postgres-db'
MEDPLUM_REDIS_HOST: 'redis'
MEDPLUM_ALLOWED_ORIGINS: '*'
MEDPLUM_INTROSPECTION_ENABLED: 'true'Web-based user interface for:
- Patient and provider management
- FHIR resource visualization and editing
- Administration and configuration
- Care coordination workflows
Access at: http://localhost:3103/
OAuth2-enabled FHIR proxy providing:
- OAuth2 Auth Code Flow with PKCE: Secure token-based authentication
- Token Management: Automatic token refresh and lifecycle management
- FHIR Proxy: Forward requests to Medplum server with authentication
- Session Management: Browser-based and Bearer token support
Key Features:
- Gzip decompression for transparent proxy operation
- Configurable OAuth2 endpoints and credentials
- Support for both browser sessions and API clients
- PKCE (Proof Key for Code Exchange) for enhanced security
Set these before docker compose up to customize Medplum:
# OAuth2 Client Credentials (required)
MEDPLUM_CLIENT_ID="your-client-id"
MEDPLUM_CLIENT_SECRET="your-client-secret"
# Medplum Server Configuration
MEDPLUM_BASE_URL="http://localhost:8103/"
MEDPLUM_APP_BASE_URL="http://localhost:3103/"
# Database Configuration
MEDPLUM_DATABASE_HOST="postgres-db"
MEDPLUM_DATABASE_PORT=5432
MEDPLUM_DATABASE_DBNAME="postgres"
MEDPLUM_DATABASE_USERNAME="postgres"
MEDPLUM_DATABASE_PASSWORD="postgres"
# Redis Configuration
MEDPLUM_REDIS_HOST="redis"
MEDPLUM_REDIS_PORT=6379
# CORS and Security
MEDPLUM_ALLOWED_ORIGINS="*"
MEDPLUM_INTROSPECTION_ENABLED="true"Configure mpclient via web form at http://localhost:8111/ or environment variables:
MEDPLUM_TOKEN_URL="http://medplum-server:8103/oauth2/token"
MEDPLUM_CLIENT_ID="your-client-id"
MEDPLUM_CLIENT_SECRET="your-client-secret"
MEDPLUM_FHIR_BASE_URL="http://medplum-server:8103/fhir/R4"- Access the Web UI: Open
http://localhost:3103/ - Login/Register: Create or use existing credentials
- Manage Data: Create, read, update, delete FHIR resources through the UI
- Manage Configuration: Configure OAuth2 clients, user access, etc.
-
Authenticate with mpclient:
# Get access token curl http://localhost:8111/auth/token \ -H "Authorization: Bearer <your-token>"
-
Use the FHIR Proxy:
curl -H "Authorization: Bearer <access-token>" \ http://localhost:8111/fhir/R4/Patient -
Create Resources:
curl -X POST http://localhost:8111/fhir/R4/Patient \ -H "Authorization: Bearer <access-token>" \ -H "Content-Type: application/fhir+json" \ -d @patient.json
mpclient implements OAuth2 Authorization Code Flow with PKCE:
- Browser Access: Visit
http://localhost:8111/ - Authentication: Click "Login with Medplum"
- Authorization: Approve access scopes
- Token Exchange: mpclient exchanges code for access/refresh tokens
- Token Management: Automatic refresh when tokens expire
- API Access: Use bearer tokens for FHIR API calls
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:8111/fhir/R4/Patientcurl -X POST http://localhost:8111/fhir/R4/Patient \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/fhir+json" \
-d '{
"resourceType": "Patient",
"name": [{"given": ["John"], "family": "Doe"}],
"birthDate": "1990-01-01"
}'curl -H "Authorization: Bearer $TOKEN" \
"http://localhost:8111/fhir/R4/Patient?name=Doe&birthdate=1990"curl -H "Authorization: Bearer $TOKEN" \
http://localhost:8111/fhir/R4/Observation?patient=<patient-id>- OAuth2 PKCE: Protects against authorization code interception attacks
- Token Expiration: Access tokens automatically refresh
- CORS Configuration: Set
MEDPLUM_ALLOWED_ORIGINSappropriately for production - Database Security: Use strong passwords for postgres-db
- Redis: Run on internal network (not exposed publicly)
- HTTPS in Production: Configure TLS termination in front of services
- Check
content-encodingheader handling - Ensure gzip decompression is working
- Verify browser console for errors
- Check FHIR_BASE_URL configuration
- Verify
MEDPLUM_TOKEN_URLis correct - Check client credentials (ID and Secret)
- Ensure Medplum server is running and healthy
- Check network connectivity between containers
- Verify postgres-db is running:
docker ps | grep postgres - Check environment variables match compose file
- Ensure proper postgres image is pulled
- Check volume permissions
- Set
MEDPLUM_ALLOWED_ORIGINSto include your domain - In development, set to
"*"(not recommended for production) - Verify mpclient is on allowed origin list
Medplum can be combined with other DHTI modules:
# Medplum with OpenMRS
dhti-cli compose add -m medplum -m openmrs
# Medplum with LangServe for AI/ML
dhti-cli compose add -m medplum -m langserve
# Full stack with analytics
dhti-cli compose add -m medplum -m neo4j -m langfuse# Medplum server health
curl http://localhost:8103/healthcheck
# mpclient status
curl http://localhost:8111/
# Database health
docker exec $(docker ps -q -f "name=postgres-db") \
pg_isready -U postgres -d postgresdocker logs dhti-medplum-server-1
docker logs dhti-medplum-app-1
docker logs dhti-mpclient-1Provide a custom medplum.config.json for advanced configuration:
MEDPLUM_CONFIG_PATH=/path/to/medplum.config.json \
docker compose up -d medplum-serverFor containerized environments without config files, all settings can be environment variables (default behavior).
Default: File-based binary storage (./binary/)
For production, consider:
- S3-compatible object storage
- Google Cloud Storage
- Azure Blob Storage
- Medplum Documentation: https://www.medplum.com/docs
- FHIR Specification: https://www.hl7.org/fhir/
- OAuth2 RFC 6749: https://tools.ietf.org/html/rfc6749
- PKCE RFC 7636: https://tools.ietf.org/html/rfc7636