Health Data Access is a reference implementation for providing patient or practitioner scoped access to clinical and/or financial health data. It uses the IBM FHIR Server together with a SMART App Launch authorization server that is built on Keycloak.
See https://alvearie.io/blog/smart-keycloak for an overview.
Currently, this pattern is packaged via docker-compose. It relies on:
- the publicly available ibmcom/ibm-fhir-server image
- publicly available images from https://github.com/Alvearie/keycloak-extensions-for-fhir
- alvearie/smart-keycloak
- alvearie/keycloak-config
Because this pattern is configured for data access (and not data ingestion), the FHIR server is configured to be read-only.
To make it easier to execute the pattern, we include a sample database under data-access/fhir/derby/sampleDB.zip.
To use this sample database, unzip it to data-access/fhir/derby
before launching the docker-compose environment for the first time.
The result should be a directory at data-access/fhir/derby/fhirDB
that has the contents of the sample database.
Execute the following commands from this repo's data-access directory (the one that has this README) to package the fhir-smart
authorization addon with the IBM FHIR Server and spin up the fhir-server and keycloak services:
mvn clean package
docker-compose up -d
Once the services are up, execute the following to configure a new realm on the keycloak service:
docker run -e FHIR_BASE_URL=http://fhir-server:9080/fhir-server/api/v4 quay.io/alvearie/keycloak-config
Finally, execute the following to tail the logs while it runs:
docker-compose logs -f
Now that the docker-compose environment is running, you can use Postman (or any other test client that supports OAuth 2.0 / OpenID Connect) to log in and access the FHIR API.
-
Discover the authentication and token endpoints from https://localhost:9443/fhir-server/api/v4/.well-known/smart-configuration
-
Create a new postman request, navigate to the Auth tab, select OAuth 2.0 and enter the following fields
- Token Name: demo (or anything else)
- Grant Type: Authorization Code
- Callback URL: http://localhost:4567/inferno/static/redirect (must match a registered callback URL for a corresponding client in Keycloak)
- Auth URL: https://localhost:8443/auth/realms/test/protocol/openid-connect/auth
- Access Token URL: https://localhost:8443/auth/realms/test/protocol/openid-connect/token
- Client ID: inferno (must match a registered client)
- Client Secret: (blank for public clients)
- Scope: launch/patient openid fhirUser offline_access patient/*.read (see SMART App Launch: Scopes and Launch Context)
- State: 1234 (any random value)
- Client Authentication: Send as Basic Auth header
-
Click
Get New Access Token
and enter the username and password of a registered user. For convenience, the defaultalvearie/keycloak-config
image creates a single user with usernamefhiruser
and passwordchange-password
. The user must have a correspondingresourceId
attribute which matches the id of the corresponding Patient resource on the FHIR server. -
Consent and proceed. By default, the consent screen will only appear for a user a single time (per client).
-
On the Token Details dialog, scroll to the bottom and look for the
patient
attribute. The value of this attribute should come from the correspondingresourceId
attribute of the user in Keycloak. If you are using the defaultalvearie/keycloak-config
config, this should bePatient1
. -
Scroll back to the top of the Token Details page and click
Use Token
. This will automatically associate this access token with your request. -
Enter a request URL like
https://localhost:9443/fhir-server/api/v4/ExplanationOfBenefit
and clickSend
. The response should contain only resources associated with this user. If you are using the defaultfhiruser
user and the sampleDB provided with this pattern, you should see a single ExplanationOfBenefit resource returned from the server.
What if the end user has access to multiple different patient records? The Keycloak extensions for FHIR provides a patient context picker.
-
Navigate to http://localhost:8080/auth/admin and login as the admin user (admin/admin by default).
-
Ensure you are on the Test realm and navigate to the Users page.
-
Click
View all users
and select the user from the list. -
Navigate to the Attributes tab and add another value to the list of values, separating each id with a single space. For example, if you are using the sampleDB, try changing
Patient1
toPatient1 Child1
and clickSave
. -
Now head back to Postman, click
Get New Access Token
, and re-enter the login credentials. This time, you should be prompted with a patient selection form. The patient information on this form is populated from information that is retrieved from the configured FHIR resource server. -
Choose a patient and press Submit. Then, on the Token Details dialog, scroll to the bottom to see the resourceId that is associated with the patient you selected in the patient attribute of the token response body.
-
Scroll back to the top of this page, click
Use Token
, and submit the request, confirming you are still able to access the ExplanationOfBenefit resources for the patient(s) associated with this user.
-
Move to helm chart and integrate with the clinical-ingestion pattern's fhir-server
-
Support user-scoped interactions (SMART App Launch for scopes beginning with
user/
instead ofpatient/
). -
FHIR Terminology Service - The IBM FHIR Server can either act as a terminology server or integrate with external terminology services (or both). The main benefit to this from a data access perspective is that it allows for advanced searching like:
- get all the patients that have an active Condition with a diagnosis code in some particular value set; or
- get all the encounters for which a clinical observation was made with a code under this particular branch of SNOMED CT
- grab the latest fhir-persistence-schema cli jar
mvn dependency:copy -Dartifact=com.ibm.fhir:fhir-persistence-schema:LATEST:jar:cli -DoutputDirectory=.
- run it against the sample db
java -jar fhir-persistence-schema-4.10.2-cli.jar --db-type derby --prop db.database=fhir/derby/fhirDB --update-schema-fhir