Credentials FHIR Query

First, a few basics

If you followed the previous guides, you will have already learned about the required JWT to access our API services. If you haven't been through that guide, stop reading and go back to the API Implementation Guide section.

External Dependencies

The Credential FHIR Query flow uses a combination of Directory lookup, authentication and authorization, and FHIR retrieval steps. Some of these steps are performed out of band, and dependent on external authorization servers to work. We will provide you with test accounts and information in this guide to connect but please remember this aspect and let us know if you find any inconsistencies with those external servers so we can work with our partners to address any misconfigured pieces in the flow.

Internal Components

The OneRecord API Services used in this flow are:

  • Directory Service
  • Integrator Service

1109

Prerequisites

In order to successfully complete a test of the FHIR Credentials flow you will need several prerequisites in place:

  • A patient/member portal site url - this is what we call a "derived auth url" and will include several query string parameters. Our integration partners provide us with sandbox portals to use for testing purposes.
  • An account used to access the patient/member portal - we will provide testing credentials for you
  • An endpoint Id - this is also provided for you

Directory Lookup and Authorization

The Directory Service exposes target FHIR endpoints, but accessing those endpoints is restricted to applications (clients/devices) registered in those target systems to which client authentication keys are assigned. These keys need to be stored in the directory in such a way that they can be retrieved based on the device using the API services.

πŸ‘

Step 1

Retrieve pre-formatted URL and navigate to portal authorization site.

Clients must interact directly with the directory to retrieve a pre-formatted URL that can be used to login a user and retrieve an authentication code. This pre-formatted url is provided by the directory along with other metadata about the FHIR endpoint in JSON format:

[
    {
        "name": "String",
        "city": "String",
        "state": "String",
        "street": "String",
        "zip": "String",
        "vendor": "String",
        "endpointStatus": "String",
        "disposition": "1|0",
        "dataType": "String",
        "derivedAuthUri": "String",
        "redirectUri": "String",
        "latitude": 42.995075,
        "longitude": -89.567826,
        "location": {
            "lat": 42.995075,
            "lon": -89.567826
        },
        "_id": "8e9cb0f7-f920-49c3-ad23-b54b8a9ebe9f",
        "parent_org": "String"
    }
]

The derivedAuthUri is the URL that can be used by an application (client) to authenticate a user and retrieve a code to be used to generate an authentication token that is passed in the HTTP header when calling a FHIR endpoint. This URL is configured on each individual endpoint and we have simplified the process by using a redirector application (web app that serves as middle man between FHIR portals and client applications) URL by default for all of our clients. See redirector application use guide for more info.

The first step in the flow is for the client to perform searches by name and zip code of the FHIR server endpoints or to retrieve a full list of endpoints available in the directory. To do a search for clinical endpoints the client will call:

  • https://stage.directory.onerecord.com/directory/v1/client/endpoint/clinical/search/{search-string}

This URL is for our development/sandbox environment - URLs will look different for production environments.

{search-string} is the name or zip code of the endpoints of interest.

For example searching for β€œEpic” endpoints on the dev environment:

  • https://stage.directory.onerecord.com/directory/v1/client/endpoint/clinical/search/epic

Will result in:

[
    {
        "name": "Epic New",
        "city": "Verona",
        "state": "WI",
        "street": "1979 Milky Way",
        "zip": "53593",
        "vendor": "Epic",
        "endpointStatus": "active",
        "disposition": "1",
        "dataType": "clinical",
        "derivedAuthUri": "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/authorize?client_id=<client-id>&redirect_uri=https%3A%2F%2Fredirector.onerecord.com%2Ffhir%2Finbound&response_type=code",
        "redirectUri": "https://redirector.onerecord.com/outbound/?portalURL=https%3A%2F%2Ffhir.epic.com%2Finterconnect-fhir-oauth%2Foauth2%2Fauthorize%3Fclient_id%3De9896805-87ce-4da3-991c-093e4d1a53c5%26redirect_uri%3Dhttps%253A%252F%252Fdevelop.onerecord.com%252Ffhir%252Fauth%26response_type%3Dcode",
        "latitude": 42.995075,
        "longitude": -89.567826,
        "location": {
            "lat": 42.995075,
            "lon": -89.567826
        },
        "_id": "8e9cb0f7-f920-49c3-ad23-b54b8a9ebe9f",
        "parent_org": "Sandbox"
    }
]

Similarly if a query for payer endpoints is desired replace the word clinical with payer in the url and use a search string that matches a payer such as humana, for example https://stage.directory.onerecord.com/directory/v1/client/endpoint/payer/search/humana.

πŸ“˜

PKCE

Some endpoints require PKCE in the OAuth process. The API client app will need to identify these endpoints by looking for 2 path variables in the derivedAuthUri namely code_challenge and code_challenge_method. The code_challenge_method specifies what method to use in the generation of the code and verifier and it will be up to the client app to generate these values and replace {code_challenge} in the derivedAuthUri with the generated code and subsequently send the verifier in the authorizationCodeVerifier body element of the token request to OR API (Step 4). As an example let's say the derivedAuthUri is https://memberlogin.bcbsfl.com/auth/oauth2/authorize?code_challenge={codechallenge}&code_challenge_method=S256&response_type=code&client_id=xxxxx&redirect_uri=https%3A%2F%2Fredirector.onerecord.com%2Finbound%2F&scope=patient%2F%2A.read. The client app should send the user to something like https://memberlogin.bcbsfl.com/auth/oauth2/authorize?code_challenge=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU&code_challenge_method=S256&response_type=code&client_id=xxxxx&redirect_uri=https%3A%2F%2Fredirector.onerecord.com%2Finbound%2F&scope=patient%2F%2A.read

πŸ‘

Step 2

Ensure redirect URL is correctly configured and check support for code and state parameters.

The client app then can use the derivedAuthUri to present a login page to the user for getting an access token to retrieve their medical records from the FHIR endpoint. This will result in an access code sent as a query parameter to the redirect_uri provided in the client parameters of the directory and reflected in the derivedAuthUri, in this case https://client.com/fhir/code. This URL must be supported by the client applications to receive the access code and optionally a state parameter in the form of query parameters. For example, the client will receive the code in a redirect to https://client.com/fhir/code?code=r234r26re6256te26t&state=1234. Some FHIR servers require the state parameter others not so to ensure you will get the proper response we recommend adding a state parameter to all urls

The code and state retrieved can now be used in the API services to get an authentication bearer token and use this token for calling FHIR endpoints.

πŸ‘

Step 3

Check configuration against against the OneRecord FHIR Directory Device (this is done for you in the demo calls).

For a client to be able to use the FHIR services, their device(s) must be linked to the or-dev-onerecord-onerecord-fhir_directory device. This OneRecord device is connected to the directory and will use the admin directory services to retrieve metadata about FHIR endpoints at runtime and call those endpoints on behalf of the client.

πŸ‘

Step 4

Get your authorization token.

To get a token the client will call the API service https://stage.integrator.onerecord.com/integrator/v1/fhir/auth/{endpoint-id}/token and pass in the authorization code and (optionally) the state in the body of the HTTP POST call.

{
    "state": "1234",
    "authorizationCode": "r234r26re6256te26t"
}

πŸ“˜

PKCE

For endpoints requiring PKCE an additional JSON element (authorizationCodeVerifier) is included in the body of the message that contains the code verifier value. For example:

{
    "state": "1234",
    "authorizationCode": "r234r26re6256te26t",
    "authorizationCodeVerifier": "vctNm4z99ZL4XSs5m1uSHuRa0CRsXI.p0C8apak_B4loVuc~w2m4Us6_OWCb-fzVHu8WEkq3eygy5-RSCY0D2wqLeC3dgaI8Px20NwfVD.RS~xyArO1OKUwIF7c-_8.K"
}

πŸ‘

Step 5

Check to ensure the endpoint id being returned is valid; check for patient id being returned and use in subsequent transactions if desired.

The {endpoint-id} is the value received in the _id field of the response from the directory from call 1, which for this example is a05bfae7-d8a0-42fa-8159-c0305066ab37 (see "_id": "a05bfae7-d8a0-42fa-8159-c0305066ab37" in JSON response from directory). This is how the API services can identify the FHIR endpoint when a service request comes in for any FHIR service.

This will give back an access token (token) and a patient Id (patId) that can be used to query FHIR endpoints.

{
    "patId": "12312-21213",
    "token": "957b880d-8e6f-4fba-82cf-b1c8359cb832",
    "tokenExpires": "28799",
    "refreshToken": "74cf555d-545c-4bfb-8563-a0f0a9261999",
    "endpointId": "a05bfae7-d8a0-42fa-8159-c0305066ab37"
}

Some FHIR servers embed the patient Id into their token so the response to their auth token call will not return a patId. In these cases the patientId is omitted from the response and not need to be sent in to the FHIR resource query call.

πŸ“˜

Refresh Token

Some servers support refresh tokens that have an extended lifetime over the access tokens. The lifetime of the refresh token is set by the FHIR server but it is not shared with the consumer in the response. Refresh token can be used to renew an access token without needing the user to go through the OAuth process again using their credentials. These refresh tokens would have to be stored in the API client in reference to an endpoint id and a patient id to be used. To use a refresh token simply use the following body when sending a request to the API service in this step, be sure to capture the new refresh token in the response since these are rotated every time they are used.

{
    "refreshToken": "74cf555d-545c-4bfb-8563-a0f0a9261999"
}

FHIR Query

πŸ‘

Step 6

It's time to get FHIR resources!

The client can now use this token and patient id to call the API to retrieve FHIR resources https://stage.integrator.onerecord.com/integrator/v1/fhir/resources/{endpoint-id}

This request is a POST with the following payload:

{
  "patientId": "12312-21213",
  "oauthToken": "957b880d-8e6f-4fba-82cf-b1c8359cb832"
}

These values come from the response to the auth endpoint:
patientId = patId
oauthToken = token

If patId is β€œnull” then you can either pass β€œnull” in the patientId property or not include this property in the payload.

πŸ‘

Step 7

Filter your FHIR Resources (if desired)

The default FHIR request will return all available FHIR resources from the endpoint. However, if you are only interested in a subset of FHIR resources, you can filter the list by including a resources array like so:

{
  "patientId": "12312-21213",
  "oauthToken": "957b880d-8e6f-4fba-82cf-b1c8359cb832",
  "resources": [
    "Immunizations"
  ]
}

For queries to payer servers we are usually interested in ExplanationOfBenefit and Coverage resources so a query into payer endpoints should look like the following:

{
  "patientId": "12312-21213",
  "oauthToken": "957b880d-8e6f-4fba-82cf-b1c8359cb832",
  "resources": [
    "Patient",
    "ExplanationOfBenefit",
    "Coverage"
  ]
}

The full list of supported FHIR resources to request from a FHIR query is:

{
  "resources": [ 
        "Patient", 
        "Immunization", 
        "AllergyIntolerance", 
        "MedicationRequest", 
        "MedicationStatement", 
        "Vitals", 
        "Labs", 
        "DiagnosticReport", 
        "Condition", 
        "Procedure", 
        "FamilyMemberHistory", 
        "DocumentReference", 
        "CareTeam",
        "CarePlan",
        "ExplanationOfBenefit", 
        "Coverage"
    ]
}

FHIR Version Conversion

Yes! We handle this as well. FHIR R4 is the latest stable release of the HL7 FHIR standard and we have a conversion feature that can be enabled for any of our customers. This feature will run automatically as part of our data retrieval and aggregation process.

As an example, an EHR FHIR server may only return DSTU2 (which is what we most commonly see today), but you only want to deal with R4, because who the heck wants to deal with multiple versions of the same clinical resource? Well no one does, so we've got your back!

Wrapping Up

In this guide we went through several steps including finding an endpoint, authentication and authorization of a user to access their FHIR data, and finally querying FHIR endpoints to retrieve data. We also saw how data can be filtered for more specific use cases. And finally we touched on our FHIR Version Conversion feature that will help ease your experience working with FHIR data.