Alvearie / keycloak-extensions-for-fhir

Keycloak extensions for FHIR
Apache License 2.0
54 stars 21 forks source link

Keycloak extensions for FHIR

The purpose of this project is to document and extend Keycloak in support of SMART on FHIR and related use cases.

Keycloak is an open source identity and access management solution.

HL7 FHIR is a specification for sharing health-related data across processes, jurisdictions, and contexts.

SMART on FHIR is a collection of specifications that focus on authentication and authorization on top of HL7 FHIR.

Background

Keycloak is configurable and extensible. Users can automate the creation of SMART scopes by either manually creating them in the admin console, by scripting, or by calling the REST APIs. However, supporting SMART launch context is a bit more tricky.

In particular, SMART App Launch extends the OAuth 2.0 / OpenID Connect token response payload with a set of launch context parameters. For example, in the case of the patient context, a SMART-enabled client application would expect a patient parameter in the token response payload (alongside the access token).

In addition, SMART App Launch defines a custom aud parameter that clients must pass on their authorization request (in addition to the fields required by OAuth 2.0 / OpenID Connect). Per the SMART "best practices" document at http://docs.smarthealthit.org/authorization/best-practices/#25-access-token-phishing-by-counterfeit-resource-servers, authorization servers should validate this field and use this same value for the aud claim in the granted access token.

Neither of these OAuth extensions are supported by Keycloak out-of-the-box and so this project can be used to fill these gaps.

Standalone app launch with launch/patient support

To launch an application in the context of a single patient, an application should:

  1. Discover the authentication and token endpoints from the FHIR server's [base]/.well-known/smart-configuration endpoint as described at https://www.hl7.org/fhir/smart-app-launch/conformance.html#using-well-known.
  2. Issue a stanard OAuth 2.0 request to the authorization endpoint with the following extensions:
    • an aud query parameter that is set to the base of the target FHIR server; and
    • a set of scopes that includes the launch/patient scope

Normally, Keycloak services such requests via its built-in Browser authentication flow. However, this built-in flow will neither validate the client's aud parameter nor allow the user to select a particular patient context.

Therefore, Keycloak extensions for FHIR provides custom Authenticators that can be used for these purposes. The extensions can be deployed to an existing Keycloak instance or packaged with Keycloak via a docker image.

Finally, the project includes a Java driver for configuring new Keycloak realms with SMART scopes, appropriately-configured Mappers, and a "SMART App Launch" browser authentication flow.

A screenshot of the SMART App Launch authentication flow

The audience validator

The Audience Validation authenticator will read the value of the aud query parameter from the authorization request and reject the request if it does not match one of the configured Allowed Audiences.

An audience validation config example for localhost

The patient context picker

The Patient Selection Authenticator must appear in the authentication flow AFTER user authentication. This authenticator reads the value of the resourceId user attribute for the authenticated user.

A patient selection form example

Mapping the user session note to the token response

As of Keycloak 12.0.0, the built-in User Session Note mapper supports mapping user session notes to custom fields in the token response. For launch/patient support, the Keycloak extensions for FHIR KeycloakConfigurator will automatically associate this mapper to the launch/patient and configure it to map the patient_id user session note to the patient field in the token response.

A screenshot of the User Session Note mapper for the patient_id note

Using the docker images

Published Docker images from this project:

By default, the alvearie/smart-keycloak image will behave identical to the Keycloak image from which it extends. Here is an example for running the image with a keycloak username and password of admin/admin:

docker run -p 8080:8080 -p 8443:8443 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin alvearie/smart-keycloak

Once you have it running, execute the alvearie/keycloak-config image to create or update a Keycloak realm with SMART App Launch support.

By default, alvearie/keycloak-config will use the following environment variables to connect to Keycloak and configure the KEYCLOAK_REALM with SMART App Launch support for a FHIR server at FHIR_BASE_URL:

Additionally, the default keycloak-config image will create a single Keycloak user in this realm with username "fhiruser" and password "change-password" (to facilitate testing).

It is possible to override these environment variables via the command line (using the -e flag), or even to pass an entirely different configuration file by specifying a docker run command. For example, to update a Keycloak server that is listening on port 8081 of the docker host with a custom configuration, you could run a command like the following:

docker run -v /local/config/dir:/config -e KEYCLOAK_BASE_URL=http://host.docker.internal:8081/auth alvearie/keycloak-config -configFile config/keycloak-config.json

See https://github.com/Alvearie/keycloak-extensions-for-fhir/tree/main/keycloak-config/src/main/resources/config for the example configurations that are shipped with this image.

Component reference

Component Description
keycloak-config A Keycloak client for configuring realms via a JSON property file.
jboss-fhir-provider A Maven project for building JBoss modules which provide JAX-RS readers and writers for FHIR media types (used by the PatientSelectionForm authenticator).
keycloak-extensions/AudienceValidator A Keycloak Authenticator for validating the aud parameter passed as part of the SMART App Launch request to the authorization endpoint (see SMART best practices for more information).
keycloak-extensions/PatientSelectionForm A Keycloak Authenticator for narrowing the scope of a given session to the context of a single patient.
keycloak-extensions/PatientPrefixUserAttributeMapper A Keycloak OIDCProtocolMapper for adding the Patient/ prefix to a user attribute; used to map the Patient resource id attribute into a valid fhirUser claim on the id_token when the fhirUser scope is requested.
keycloak-extensions/UserAttributeMapper A forked copy of the Keycloak User Attribute mapper that has been extended to support mapping user attributes to custom fields in the token response payload (rather than claims in the issued tokens).

Building the docker images

To build the docker images:

  1. Clone or download the project and navigate to the root of the project.
  2. Build the project via mvn clean install -DskipTests.
  3. Build the alvearie/smart-keycloak image via docker build . -t alvearie/smart-keycloak.
  4. Build the alvearie/keycloak-config image via docker build . -f keycloak-config/Dockerfile -t alvearie/keycloak-config.

Contributing

Are you using Keycloak for SMART on FHIR or other health APIs? If so, we'd love to hear from you.

Connect with us on chat.fhir.org or open an issue or pull request.

See CONTRIBUTING.md for more information and CODE_OF_CONDUCT.md for our code of conduct.