A Medplum Application + Bot that issues SMART Health Cards using the FHIR Operation $health-cards-issue as defined by the Issue Verifiable Credential FHIR spec.
Uses the library kill-the-clipboard.
Demo available at https://vintasoftware.github.io/medplum-health-card-demo/
- Immunization Filtering: Filter patient immunizations by date range
- QR Code Generation: Generate SMART Health Card QR codes that can be scanned by healthcare providers
- User-Friendly Interface: Built with React Medplum components
- SMART Health Card Issuance: Generate health cards for any FHIR resource type, including immunizations
- Date Filtering: Filter resources by date using
_sinceparameter - Value Set Filtering: Filter resources by specific value sets (NOTE: requires UMLS Terminology, a premium Medplum feature)
This is a monorepo containing two main components:
- Bots (
src/bots/): Medplum bot for SMART Health Card issuance using the FHIR Operation$health-cards-issue, built with esbuild - App (
src/app/): Patient-facing React application for generating SMART Health Cards, built with Vite
# Install all dependencies (root + app workspace)
npm install
# Build everything (bots + app)
npm run build
# Build only bots
npm run build:bots
# Build only app
npm run build:app
# Run tests (for bots)
npm test
# Start app development server
npm run dev:appIf you haven't already done so, follow the instructions in this tutorial to register a Medplum project.
This project uses the Medplum CLI for bot management. Follow these steps to deploy your bot:
-
Build the bot code:
npm run build:bots
-
Get your Project ID:
- Navigate to your Medplum project's admin panel
- Copy your Project ID
-
Create the bot using Medplum CLI:
npx medplum bot create health-cards-demo-bot <PROJECT_ID> src/bots/health-cards-demo-bot.ts dist/health-cards-demo-bot.js
This will:
- Create a Bot resource in Medplum
- Add the bot to
medplum.config.json - Create a ProjectMembership linking the bot to your project
-
Deploy the bot code:
npx medplum bot deploy health-cards-demo-bot
-
Deploy the custom FHIR operation:
npm run deploy:operation
This creates the
$health-cards-issueoperation definition that links to your bot (by the namehealth-cards-demo-bot). -
Set the bot as
system:npx medplum patch Bot/<BOT_ID> '[{"op":"add","path":"/system","value":true}]'
Replace
<BOT_ID>with the bot ID frommedplum.config.json(theidfield forhealth-cards-demo-bot). This is necessary to allow the bot to access the SHC secret key. -
Set the Patient user access policy for executing the custom FHIR operation:
npx medplum post AccessPolicy "$(cat patient-access-policy.json)"This creates an Access Policy that allows Patient users to access the
BotandOperationDefinitionresources needed to execute the health card generation bot. -
Configure the bot secrets:
- See the section Bot Secrets Configuration below.
The bot requires these secrets to be configured in Medplum:
SHC_ISSUER: Issuer URL for the SMART Health CardsHEALTH_CARD_PUBLIC_KEY: ES256 public keyHEALTH_CARD_PRIVATE_KEY: ES256 private key
You can use the public/private key pair from the example issuer https://spec.smarthealth.cards/examples/issuer. Do NOT use those values in production:
SHC_ISSUER=https://spec.smarthealth.cards/examples/issuer
HEALTH_CARD_PUBLIC_KEY={"kty": "EC","kid": "3Kfdg-XwP-7gXyywtUfUADwBumDOPKMQx-iELL11W9s","use": "sig","alg": "ES256","crv": "P-256","x": "11XvRWy1I2S0EyJlyf_bWfw_TQ5CJJNLw78bHXNxcgw","y": "eZXwxvO1hvCY0KucrPfKo7yAyMT6Ajc3N7OkAB6VYy8","crlVersion": 1}
HEALTH_CARD_PRIVATE_KEY={"kty": "EC","kid": "3Kfdg-XwP-7gXyywtUfUADwBumDOPKMQx-iELL11W9s","use": "sig","alg": "ES256","crv": "P-256","x": "11XvRWy1I2S0EyJlyf_bWfw_TQ5CJJNLw78bHXNxcgw","y": "eZXwxvO1hvCY0KucrPfKo7yAyMT6Ajc3N7OkAB6VYy8","d": "FvOOk6hMixJ2o9zt4PCfan_UW7i4aOEnzj76ZaCI9Og"}- Go to the "Secrets" page in app.medplum.com
- Add the three secrets with the example values (see above)
A React application that allows patients to generate SMART Health Cards from their immunization records.
Before running the app, deploy the health cards bot (see Bot Deployment section above).
To allow patients to self-register, set the patient access policy as the default.
- Navigate to app.medplum.com Project page and select your project.
- In the "Edit" tab, set the "Default Patient Access Policy" field to your patient access policy and click "Update".
For more details, see the Open Patient Registration documentation.
A reCAPTCHA configuration is required for the registration form to work.
- Create a new reCAPTCHA configuration to get the site key and secret key at google.com/recaptcha/admin/create.
- Go to app.medplum.com, go to Project, then Sites. Create a Site with domains
localhostand127.0.0.1and set the reCAPTCHA site key and secret key. - Keep the reCAPTCHA site key at hand to set it as an environment variable (see the next section).
Create a Client Application in your Medplum project to get the client ID and secret:
- Create a Client Application in your Medplum project
- Inside the
src/appdirectory, copy the.env.defaultsfile to.envand configure the environment variables:
cd src/app
cp .env.defaults .env- Add the following to your
.envfile:
MEDPLUM_BASE_URL=https://api.medplum.com # or your Medplum server URL
MEDPLUM_CLIENT_ID=your-client-id
MEDPLUM_PROJECT_ID=your-project-id # Required for patient registration
MEDPLUM_RECAPTCHA_SITE_KEY=your-recaptcha-site-key # Required for patient registrationFrom the root directory:
# Install dependencies (installs for both bots and app)
npm install
# Start the app development server
npm run dev:appThe app runs on http://localhost:3000/
Alternatively, you can run commands directly from the app directory:
cd src/app
npm run dev- New users: Click "Sign in" and then "Register here" to create a new patient account
- Existing users: Sign in as a Patient user
- (Optional) Filter your immunizations by date
- Click "Generate Health Card" to create a health card with your immunizations
- Scan the QR code with a SMART Health Card reader app
After making changes to the bot code:
# Build the updated code
npm run build:bots
# Deploy to Medplum
npx medplum bot deploy health-cards-demo-botThe $health-cards-issue custom FHIR Operation is implemented in the bot with these parameters:
Required:
subject: Patient resource referencecredentialType: FHIR resource type to include in the health card
Optional:
_since: ISO8601 date for filtering (e.g., "2023-01-01")credentialValueSet: Value set URIs for filtering (e.g., "https://terminology.smarthealth.cards/ValueSet/immunization-covid-all"). Multiple value sets can be specified using multiple parameters with AND logic. NOTE: requires UMLS Terminology, a premium Medplum feature. Grab SMART Health Cards terminology from terminology.smarthealth.cards and add it to your Medplum instance.includeIdentityClaim: Patient data to include (e.g.,Patient.name)
Example Request (with filters):
{
"resourceType": "Parameters",
"parameter": [
{
"name": "subject",
"valueReference": {"reference": "Patient/patient-123"}
},
{
"name": "credentialType",
"valueUri": "Immunization"
},
{
"name": "credentialValueSet",
"valueUri": "https://terminology.smarthealth.cards/ValueSet/immunization-covid-all"
},
{
"name": "_since",
"valueDateTime": "2023-01-01"
}
]
}# Code quality (for bots)
npm run check:fix
# Testing (for bots)
npm run test:watch
# Tests with coverage (for bots)
npm run test:coverage
# Linting (for bots)
npm run lint:fix# Start development server
npm run dev:app
# Preview production build
npm run preview:app
# Linting (for app, uses Biome)
npm run lint:app:fixThis project includes a GitHub Actions workflow to automatically deploy the patient-facing app to GitHub Pages.
-
Enable GitHub Pages for your repository:
- Go to your repository Settings → Pages
- Under "Build and deployment", select "GitHub Actions" as the source
-
Configure GitHub Secrets:
Add the following secrets to your repository (Settings → Secrets and variables → Actions → New repository secret):
MEDPLUM_BASE_URL: e.g.,https://api.medplum.comMEDPLUM_CLIENT_IDMEDPLUM_PROJECT_IDMEDPLUM_RECAPTCHA_SITE_KEY
-
Configure base path (if needed):
If your repository is hosted at
https://username.github.io/repository-name/(not at a custom domain or root), you'll need to update the Vite config insrc/app/vite.config.tsto set the base path:export default defineConfig({ base: '/repository-name/', // Add this line // ... rest of config })
The workflow automatically deploys when you push to the main branch, or you can manually trigger it from the Actions tab in your GitHub repository.
After deployment, your app will be available at:
https://username.github.io/repository-name/(for project pages)
For larger FHIR bundles, prefer using SMART Health Links. The Kill the Clipboard Library also supports SMART Health Link generation and it provides a Medplum Demo project.
MIT License - see LICENSE file for details.
This project is maintained by Vinta Software. We offer design and development services for healthcare companies. If you need any commercial support, feel free to get in touch: contact@vinta.com.br