/prior-auth

Da Vinci Prior Authorization Reference Implementation

Primary LanguageJavaApache License 2.0Apache-2.0

Prior Authorization Reference Implementation

The Da Vinci Prior Authorization Reference Implementation (RI) is a software project that conforms to the Prior Authorization Implementation Guide (IG) and the Prior Authorization IG Proposal developed by the Da Vinci Project within the HL7 Standards Organization.

Requirements

  • Java JDK 11

Getting Started

Build, test, and start the Prior Authorization microservice:

./gradlew embedCdsLibrary
./gradlew installBootDist
./gradlew clean check
./gradlew bootRun

To run the microservice in debug mode (which enables debug log statements, an endpoint to view the database, and and endpoint to prefill the database with test data) use:

./gradlew bootRun --args='debug'

Access the microservice:

curl http://localhost:9015/fhir/metadata
curl http://localhost:9015/fhir/Bundle
curl http://localhost:9015/fhir/Claim
curl http://localhost:9015/fhir/ClaimResponse

Submit a prior authorization request:

curl -X POST
     -H "Content-Type: application/json"
     -d @src/test/resources/bundle-prior-auth.json
     http://localhost:9015/fhir/Claim/\$submit

End-To-End DRLS PAS Docker configuration:

You can find complete end-to-end fullstack set up guides for DRLS PAS at the following links:

Developer Environment Set Up - Follow this guide if you are a developer and intend on making code changes to the DRLS PAS project. This guide follows a much more technical set up process.

Production Environement Set Up - Follow this guide if you are not a developer and do not intend on making code changes to the DRLS PAS project. This guide covers two options for running DRLS PAS, both of which are less techincal than the developer set up.

Configuration Notes

The server on the dev branch is always configured to run on Logicahealth. If you are running locally or on another cloud server there are a few extra configuration steps:

  1. This server expects to be running on HTTPS. If you are not using SSL the authorization will fail. Either follow the steps under "SSL Certificates" below to add SSL to your local version, or modify getServiceBaseUrl() in Endpoint.java to use http.
  2. The default tokenUri points to LogicaHealth. Update tokenUri in Metadata.java to be the correct host.
  3. If using the MITRE DTR Reference Implementation there are is a PAS config under src/components/PriorAuth which must be updated.

FHIR Services

The service endpoints in the table below are relative to http://localhost:9015/fhir. patient is the first identifier.value on the Patient referenced in the submitted Claim.

Service Methods Description
/metadata GET The FHIR capabilities interaction that returns a FHIR CapabilityStatement resource describing these services.
/Bundle?patient.identifier={patient} GET The FHIR Bundle endpoint returns all the Bundles that were submitted to the Claim/$submit operation for patient.
/Bundle?patient.identifier={patient}&status={status} GET The FHIR Bundle endpoint returns all the Bundles that were submitted to the Claim/$submit operation for patient with the given status.
/Bundle?identifier={id}&patient.identifier={patient} GET Gets a single Bundle by id and patient
/Bundle?identifier={id}&patient.identifier={patient}&status={status} GET Gets a single Bundle by id, patient, and status.
/Bundle?identifier={id}&patient.identifier={patient} DELETE Deletes a single Bundle by id and patient
/Claim?patient.identifier={patient} GET The FHIR Claim endpoint returns all the Claims that were submitted to the Claim/$submit operation for patient.
/Claim?patient.identifier={patient}&status={status} GET The FHIR Claim endpoint returns all the Claims that were submitted to the Claim/$submit operation for patient with the given status.
/Claim?identifier={id}&patient.identifier={patient} GET Gets a single Claim by id and patient
/Claim?identifier={id}&patient.identifier={patient}&status={status} GET Gets a single Claim by id, patient, and status.
/Claim?identifier={id}&patient.identifier={patient} DELETE Deletes a single Claim by id and patient
/Claim$submit POST Submit a Bundle containing a Prior Authorization Claim with all the necessary supporting resources. The response to a successful submission is a ClaimResponse.
/ClaimResponse?patient.identifier={patient} GET The FHIR ClaimResponse endpoint returns all the ClaimResponses that were generated in response to Claim/$submit operations for patient.
/ClaimResponse?patient.identifier={patient}&status={status} GET The FHIR ClaimResponse endpoint returns all the ClaimResponses that were generated in response to Claim/$submit operations for patient with the given status.
/ClaimResponse?identifier={id}&patient.identifier={patient} GET Gets a single ClaimResponse by id and patient.
/ClaimResponse?identifier={id}&patient.identifier={patient}&status={status} GET Gets a single ClaimResponse by id, patient, and status.
/ClaimResponse?identifier={id}&patient.identifier={patient} DELETE Deletes a single ClaimResponse by id and patient.
/Subscription POST Submit a new Subscription for a pended or partial ClaimResponse using rest-hook or websockets.
/Subscription?identifier={id}&patient.identifier={patient}&status={status} GET Gets a single Subscription defined with id for patient.
/Subscription?identifier={id}&patient.identifier={patient} DELETE Deletes (todo update which id this uses and if it deletes all or just a single).

Note About IDs: The Prior Authorization service generates a preAuthRef id when a successful Claim/$submit operation is performed. If the submitted resources do not contain ids their ids will be updated to id. The id referenced by the identifier in the request parameters is the preAuthRef id. The Bundle that was submitted will subsequently be available at /Bundle?identifier={id}&patient.identifier={patient}, and the Claim from the submission will be available at /Claim?identifier={id}&patient.identifier={patient}, and the ClaimResponse will also be available at /ClaimResponse?identifier={id}&patient.identifier={patient}. All three resources will share the same id.

Note About DELETE: A DELETE by id to one resource (i.e. Bundle, Claim, ClaimResponse) is a Cascading Delete and it will delete all associated and related resources.

If debug mode is enabled the following endpoints are available for use at http://localhost:9015/fhir:

Service Methods Description
/debug/Bundle GET HTML page to view the Bundle table in the database
/debug/Claim GET HTML page to view the Claim table in the database
/debug/ClaimResponse GET HTML page to view the ClaimResponse table in the database
/debug/ClaimItem GET HTML page to view the ClaimItem table in the database
/debug/Subscription GET HTML page to view the Subscription table in the database
/debug/PopulateDatabaseTestData POST Insert test data into the database. Remove any of the existing test data and insert a fresh copy. All test data has a timestamp in 2200 so it can easily be identifier
/debug/Convert POST Convert a CQL body (string) into Elm (xml)
/debug/ReleaseClaim?identifier={id} GET Releases a claim by id from a pended state and triggers the subscription workflow.
/$expunge POST Delete all entried in all tables

Authorization

SSL Certificates

This Reference Implementation requires certificates for SSL traffic. By default this is disabled since the hosted version on Logica Health adds its own certificated. When running on localhost you must enable https traffic. Configuration details are in src/main/resources/application.properties. The enable the default SSL configurations, remove the comments from the following lines:

server.ssl.key-store=pas_keystore.p12
server.ssl.key-store-password=password
server.ssl.keyStoreType=PKCS12
server.ssl.keyAlias=pas

To create your own certificate run the following from the root directory of this project:

$ keytool -genkey -alias pas -keystore pas_keystore.p12 -keyalg RSA -storetype PKCS12

You will be prompted to create a password for the keystore and then enter details about the certificate. Be sure to update server.ssl.key-store-password above with the new password you just created.

Server to Server OAuth

The recommended way of authorization is server to server OAuth. The implementation details are provided in the Bulk Data Transfer IG.

Register a new client /auth/register

See wiki.

Token request /auth/token

A registered client must obtain an access token before making any requests to the server. This is used to validate where the request is coming from and is used in the AuditEvent for creating an audit trail of all requests.

Following the client_credentials OAuth 2.0 grant flow the process is:

HTTP POST
/auth/token?scope={launch scope}
&grant_type=client_credentials
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion={signed JWT token}

Th client_assertion is a signed JWT token following this structure.

The response will be a JSON object containing the access_token. This token will only be valid for 5 minutes. In all requests to the server you must add the Authorization: Bearer {access_token} header to the HTTP request.

Contents of /Claim/$submit Submission

The body of the /Claim/$submit operation are as follows:

 + Bundle
 |
 +-+ entry
   |
   +-- Claim
   |
   +-- QuestionnaireResponse
   |
   +-- DeviceRequest
   |
   +-- Other Resources (Patient, Practitioner, Coverage, Condition, Observation)

The first entry of the submitted Bundle should contain a Claim, followed by a QuestionnaireResponse which includes answers in response to questions presented by Da Vinci Documentation Templates and Rules (DTR), then the DeviceRequest (or other resource type) that actually requires the prior authorization, followed by all supporting FHIR resources including the Patient, Practitioner, Coverage, and relevant Condition and Observation resources used in DTR calculations or otherwise used as supporting information.

To cancel the Claim submit a Claim resource with the id of the Claim to cancel and set the status to cancelled. If the Claim exists and is not already cancelled the database will be update to reflect the cancellation.

Response of the /Claim/$submit Operation

Assuming the structure and contents of the submitted Bundle are adequate, the service will responsed with a ClaimResponse as detailed below. Otherwise, the service will respond with an OperationalOutcome containing an error message.

 + ClaimResponse
 + ClaimResponse.id = {id}
 + ClaimResponse.status
 + ClaimResponse.type
 + ClaimResponse.use = "preauthorization"
 + ClaimResponse.patient = { reference: Patient }
 + ClaimResponse.created
 + ClaimResponse.insurer
 + ClaimResponse.request = { reference: Claim/{id} }
 + ClaimResponse.outcome
 + ClaimResponse.disposition
 + ClaimResponse.preAuthRef = {prior authorization number}

With a successful submission, the actual Prior Authorization Number is located in the ClaimResponse.preAuthRef field.

For example:

{
  "resourceType": "ClaimResponse",
  "id": "536d41f2-0273-4807-a0e6-8d9909146667",
  "status": "active",
  "type": {
    "coding": [
      {
        "system": "http://terminology.hl7.org/CodeSystem/claim-type",
        "code": "professional",
        "display": "Professional"
      }
    ]
  },
  "use": "preauthorization",
  "patient": { "reference": "Patient/pat013" },
  "created": "2019-05-04T15:32:06+00:00",
  "insurer": {
    "display": "Unknown"
  },
  "request": { "reference": "Claim/536d41f2-0273-4807-a0e6-8d9909146667" },
  "outcome": "complete",
  "disposition": "Granted",
  "preAuthRef": "536d41f2-0273-4807-a0e6-8d9909146667"
}

A successful submission will return a ClaimResponse with the status code 201 with the Location header set to the location of the newly created ClaimResponse.

Contents of /Subscription Submission

POSTing to the /Subscription endpoint is used to submit a new Rest-Hook or WebSocket based subscription for a pended or partial ClaimResponse. Once an update has been made a notification will be sent to the subscription. The subscriber can then poll using the original identifier to obtain the most updated ClaimResponse.

The body for a Rest-Hook subscription is as follows:

{
  "resourceType": "Subscription",
  "status": "requested",
  "criteria": "identifier={id}&patient.identifier={patient}&status=active",
  "channel": {
    "type": "rest-hook",
    "endpoint": "http://localhost:9090/fhir/SubscriptionNotification?identifier={id}&patient.identifier={patient}&status=active"
  }
}

For more information on rest-hook subscriptions jump to Using Rest-Hook Subscriptions.

The body for a WebSocket subscription is as follows:

{
  "resourceType": "Subscription",
  "status": "requested",
  "criteria": "identifier={id}&patient.identifier={patient}&status=active",
  "channel": {
    "type": "websocket"
  }
}

For more information on WebSocket subscriptions jump to Using WebSocket Subscriptions.

Response to /Subscription Submission

Assuming the contents of the Subscription are valid and the server is able to process the request correctly it will respond with the same Subscription resource and the id set to the logical id of the Subscription. For example, the response to a WebSocket Subscription would be:

{
  "resourceType": "Subscription",
  "id": "{new subscription id}",
  "status": "active",
  "criteria": "identifier={id}&patient.identifier={patient}&status=active",
  "channel": {
    "type": "websocket"
  }
}

When using WebSocket subscriptions the id provided in the response is the id used in all WebSocket messages.

Using Rest-Hook Subscriptions

Rest-Hook subscriptions require the client to operate an external server which can operate REST endpoints. The client server for this RI is provided in the Prior Auth Client Github. By default this client will start the server at http://localhost:9090/fhir and will receive notifications on the /SubscriptionNotification?identifier={id}&patient.identifier={patient}&status=active endpoint. More details can be found on the Prior Auth Client Github.

The flow for Rest-Hook subscriptions is as follows:

  1. Start the Prior Auth service
  2. Start the Prior Auth Client service
  3. Submit a Claim to /Claim/$submit
  4. Subscribe to a pended or partial ClaimResponse by submitting a Rest-Hook subscription to /Subscription
  5. When an update is ready the Prior Auth service will send a POST to the channel.endpoint provided in the Subscription
  6. The Prior Auth Client will receive the notification and poll for the updated ClaimResponse resource. If the ClaimResponse has outcome complete or error the client performs a DELETE on /Subscription

Using WebSocket Subscriptions

WebSocket subscriptions do not require the client to operate an external REST server, however

To use WebSocket subscriptions the client must submit a Subscription as well as bind the Subscription to a WebSocket using the WebSocket client. The steps to do that are as follows:

  1. Start the Prior Auth service
  2. Submit a Claim to /Claim/$submit
  3. Subscribe to a pended or partial ClaimResponse by submitting a WebSocket subscription to /Subscription. The response to this submission will contain the logical id of the Subscription used in step 5
  4. The client should connect to the WebSocket ws://{BASE}/fhir/connect and subscribe to /private/notification. For localhost the {BASE} is localhost:9015. To connect to the RI on LogicaHealth use wss://davinci-prior-auth.logicahealth.org/fhir/connect.
  5. The client then binds the Subscription id by sending the message bind: id (using the logical id of the Subscription) to /subscribe over the WebSocket
  6. If the id is bound successfully the client receives the message bound: id over {BASE}/fhir/private/notification
  7. When an update is ready the Prior Auth service will send the message ping: id over {BASE}/fhir/private/notification
  8. The client can then poll for the updated ClaimResponse

The Prior Auth Client Github provides a WebSocket client in src/main/resources/index.html. This client handles steps 4 and 5 through the web interface. Details on how to use the client are provided in the Prior Auth Client README.

Demonstration

This project can be demonstrated in combination with the Da Vinci Coverage Requirements Discovery (CRD), CRD request generator, and Documentation Templates and Rules (DTR) projects.

  1. Follow the CRD instructions to start the ehr-server (i.e. gradle tomcatRun within {CRD}/ehr-server)
  2. Follow the CRD instructions to start the CDS Hooks server (i.e. gradle bootRun within {CRD}/server)
  3. Follow the crd-request-generator instructions to launch the request generator (i.e. npm start within that project)
  4. Follow the dtr instructions to launch the DTR application (i.e. npm start within that project)
  5. Follow the Getting Started instructions above to start the Prior Authorization Claim/$submit service (i.e. ./gradlew run)
  6. Using the crd-request-generator application (i.e. browsing http://localhost:3000):
  • select stu3
  • enter Age 40
  • enter Gender Male
  • select Code Oxygen Thing - E0424
  • select Massachusetts (in both Patient and Practitioner State)
  • select Include Prefetch
  • click Submit

Request Generator Application

  1. In the display CDS Hook card, select SMART App, which will open up a Questionnaire Form.

CDS Hook Card

  1. Scroll down to the bottom of the Questionnaire Form and click Submit.
  2. A fancy alert will tell you the prior authorization request has been granted. Use the browser debug tools to view interesting messages on the console.

Alert Message

Docker

Build the docker image:

docker build -t hspc/davinci-prior-auth:latest .

Run the docker image:

docker run -p 9015:9015 -it --rm --name davinci-prior-auth hspc/davinci-prior-auth:latest

If you are building the docker image locally from a MITRE machine you must copy over the BA Certificates to the Docker image. Download the MITRE BA NPE CA-3 and MITRE BA ROOT certs from the MII. Copy the two files to the root directory of this project.

Build and run using:

docker build -f Dockerfile.mitre -t mitre/davinci-prior-auth .
docker run -p 9015:9015 -it --rm --name davinci-prior-auth mitre/davinci-prior-auth

Questions and Contributions

Questions about the project can be asked in the Da Vinci PAS stream on the FHIR Zulip Chat.

This project welcomes Pull Requests. Any issues identified with the RI should be submitted via the GitHub issue tracker.

As of October 1, 2022, The Lantana Consulting Group is responsible for the management and maintenance of this Reference Implementation. In addition to posting on FHIR Zulip Chat channel mentioned above you can contact Corey Spears for questions or requests.