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.
- Java JDK 11
Build, test, and start the Prior Authorization microservice:
./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:9000/fhir/metadata
curl http://localhost:9000/fhir/Bundle
curl http://localhost:9000/fhir/Claim
curl http://localhost:9000/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:9000/fhir/Claim/\$submit
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:
- 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()
inEndpoint.java
to usehttp
. - The default tokenUri points to LogicaHealth. Update
tokenUri
inMetadata.java
to be the correct host. - If using the MITRE DTR Reference Implementation there are is a PAS config under src/components/PriorAuth which must be updated.
The service endpoints in the table below are relative to http://localhost:9000/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 Bundle s that were submitted to the Claim/$submit operation for patient . |
/Bundle?patient.identifier={patient}&status={status} |
GET |
The FHIR Bundle endpoint returns all the Bundle s 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 Claim s that were submitted to the Claim/$submit operation for patient . |
/Claim?patient.identifier={patient}&status={status} |
GET |
The FHIR Claim endpoint returns all the Claim s 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 ClaimResponse s 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 ClaimResponse s 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 successfulClaim/$submit
operation is performed. If the submitted resources do not contain ids their ids will be updated toid
. Theid
referenced by theidentifier
in the request parameters is the preAuthRefid
. TheBundle
that was submitted will subsequently be available at/Bundle?identifier={id}&patient.identifier={patient}
, and theClaim
from the submission will be available at/Claim?identifier={id}&patient.identifier={patient}
, and theClaimResponse
will also be available at/ClaimResponse?identifier={id}&patient.identifier={patient}
. All three resources will share the sameid
.
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:9000/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) |
/$expunge |
POST |
Delete all entried in all tables |
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.
The recommended way of authorization is server to server OAuth. The implementation details are provided in the Bulk Data Transfer IG.
See wiki.
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.
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.
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
.
POST
ing 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.
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.
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:
- Start the Prior Auth service
- Start the Prior Auth Client service
- Submit a Claim to
/Claim/$submit
- Subscribe to a pended or partial ClaimResponse by submitting a Rest-Hook subscription to
/Subscription
- When an update is ready the Prior Auth service will send a
POST
to thechannel.endpoint
provided in the Subscription - The Prior Auth Client will receive the notification and poll for the updated ClaimResponse resource. If the ClaimResponse has outcome
complete
orerror
the client performs aDELETE
on/Subscription
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:
- Start the Prior Auth service
- Submit a Claim to
/Claim/$submit
- 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 - The client should connect to the WebSocket
ws://{BASE}/fhir/connect
and subscribe to/private/notification
. For localhost the{BASE}
islocalhost:9000
. To connect to the RI on LogicaHealth usewss://davinci-prior-auth.logicahealth.org/fhir/connect
. - 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 - If the id is bound successfully the client receives the message
bound: id
over{BASE}/fhir/private/notification
- When an update is ready the Prior Auth service will send the message
ping: id
over{BASE}/fhir/private/notification
- 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.
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.
- Follow the
CRD
instructions to start theehr-server
(i.e.gradle tomcatRun
within{CRD}/ehr-server
) - Follow the
CRD
instructions to start the CDS Hooksserver
(i.e.gradle bootRun
within{CRD}/server
) - Follow the
crd-request-generator
instructions to launch the request generator (i.e.npm start
within that project) - Follow the
dtr
instructions to launch the DTR application (i.e.npm start
within that project) - Follow the Getting Started instructions above to start the Prior Authorization
Claim/$submit
service (i.e../gradlew run
) - Using the
crd-request-generator
application (i.e. browsinghttp://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
- In the display CDS Hook card, select
SMART App
, which will open up a Questionnaire Form.
- Scroll down to the bottom of the Questionnaire Form and click
Submit
. - A fancy
alert
will tell you the prior authorization request has been granted. Use the browser debug tools to view interesting messages on theconsole
.
Build the docker image:
docker build -t hspc/davinci-prior-auth:latest .
Run the docker image:
docker run -p 9000:9000 -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 9000:9000 -it --rm --name davinci-prior-auth mitre/davinci-prior-auth
Questions about the project can be asked in the DaVinci 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.