The NXT FHIR API authorization implementation follows the requirements laid out by the SMART App Launch Framework v1.0.0 specifications. This document builds on top of the above specification to clarify the implementation details of the NXT framework.
Application registration
In order to be able to access protected resources in the NXT FHIR APi, a client application has to be registered with the system. In order to do that you need to provide us with a few pieces of information:
- Application
name
- Application type: confidential (an application that can protect a secret), public (example a browser based SPA), native, system (a server-to-server type application)
- redirect uri - used to redirect the browser to your application after the authorization workflow as well as confirm your identity
- JWKS uri - for system applications this is the URL where your public signing key information can be retrieved
After registration we will generate a client_id
and a shared secret
that will be sent securely to you.
Authorization URLs
Each deployed NXT FHIR service advertises its authorization specific URLs using the smart-configuration
endpoint. In order to retrieve the conformance document you should perform a GET
request on the endpoint smart-configuration
url:
Example
Request
GET https://r4cert.medicasoft.us/api/fhir/.well-known/smart-configuration
Response
{
"authorization_endpoint": "https://r4cert.medicasoft.us/api/security/smart/authorize",
"token_endpoint": "https://r4cert.medicasoft.us/api/security/smart/token",
"token_endpoint_auth_methods_supported": [
"client_secret_basic"
],
"registration_endpoint": "https://dev-53834000.okta.com/oauth2/aus4iqk1j2177jl9N5d7/v1/clients",
"scopes_supported": [
"openid",
"profile",
"launch",
"launch/patient",
"patient/*.read",
"user/*.read",
"offline_access",
"system/*.read"
],
"response_types_supported": [
"code",
"code id_token",
"id_token",
"refresh_token"
],
"introspection_endpoint": "https://dev-53834000.okta.com/oauth2/aus4iqk1j2177jl9N5d7/v1/introspect",
"revocation_endpoint": "https://dev-53834000.okta.com/oauth2/aus4iqk1j2177jl9N5d7/v1/revoke",
"capabilities": [
"launch-ehr",
"client-public",
"client-confidential-symmetric",
"context-ehr-patient",
"sso-openid-connect",
"launch-standalone",
"context-standalone-patient",
"permission-offline",
"permission-patient",
"context-banner",
"context-style",
"permission-user"
],
"code_challenge_methods_supported": [
"S256"
]
}
Supported Scopes
The NXT FHIR APi supports the following scopes:
launch/patient, openid, fhirUser, offline_access, patient/Medication.read, patient/AllergyIntolerance.read, patient/CarePlan.read, patient/CareTeam.read, patient/Condition.read, patient/Device.read, patient/DiagnosticReport.read, patient/DocumentReference.read, patient/Encounter.read, patient/Goal.read, patient/Immunization.read, patient/Location.read, patient/MedicationRequest.read, patient/Observation.read, patient/Organization.read, patient/Patient.read, patient/Practitioner.read, patient/Procedure.read, patient/Provenance.read, patient/PractitionerRole.read, user/Medication.read, user/AllergyIntolerance.read, user/CarePlan.read, user/CareTeam.read, user/Condition.read, user/Device.read, user/DiagnosticReport.read, user/DocumentReference.read, user/Encounter.read, user/Goal.read, user/Immunization.read, user/Location.read, user/MedicationRequest.read, user/Observation.read, user/Organization.read, user/Patient.read, user/Practitioner.read, user/Procedure.read, user/Provenance.read, user/PractitionerRole.read, system/*.read
Launch sequences
The NXT FHIR API implements the following SMART launch sequences
EHR Launch
Your application is launched from the HealthCenter PHR user interface.
-
The HealthCenter user interface will open your application URL in a new browser page, along with an
iss
and alaunch
parameter.iss
is the FHIR API url that you can use to discover the API endpointlaunch
is an opaque token that will be exchanged for an access token later on. It is also used to provide the application launch context (e.g. patient selected in HealthCenter at the time of launch).Example
GET https://inferno.healthit.gov/suites/custom/smart/launch?iss=https://r4cert.medicasoft.us/api/fhir&launch=12345678
-
Your application retrieves the SMART configuration from the
smart-configuration
endpointExample
GET https://r4cert.medicasoft.us/api/fhir/.well-known/smart-configuration
-
Your application then follows the standalone launch sequence as described below except that it should also pass the received
launch
parameter to theauthorize
endpointExample
GET https://r4cert.medicasoft.us/api/security/smart/authorize?response_type=code&redirect_uri=[redirect_uri]&client_id=[client_id]&state= [client_application_state]&scope=[requested_scopes]&aud=https%3A%2F%2Fr4cert.medicasoft.us%2Fapi%2Ffhir&launch=[received_launch_parameter]
Standalone launch
In the standalone launch, you application initiates the aouthorization flow in order to connect to the FHIR API endpoint.
-
Your application requests an authorization code
Your application will snd a GET request to the
authorization
endpoint with the following query parameters:response_type
- alwayscode
client_id
- the application client id received from MedicaSoft during the Application Registration processredirect_uri
- your application redirect URLscope
- requested application scopes (see). For a patient facing client application you should send some or all of thepatient
access scopes, for a practitioner facing application you should send theuser
scopes.state
- this is an opaque identifier generated by your application that identifies this sessionaud
- FHIR API endpoint URL
Example
GET https://r4cert.medicasoft.us/api/security/smart/authorize?response_type=code&redirect_uri=[redirect_uri]&client_id=[client_id]&state= [client_application_state]&scope=[requested_scopes]&aud=https%3A%2F%2Fr4cert.medicasoft.us%2Fapi%2Ffhir
-
The authorization server authenticates and authorizes the user
If the authentication is successful, the authorization server redirects the user to the consent page, otherwise it return a
401
error. The user authorizes some or all of the requested scopes. The authorization server redirects the browser to the redirect URL you supplied during the [Application Registration] (#application-registration) and appends the following parameters:code
- the authorization code is a token generated by the authorization server that will be exchanged for an access tokenstate
- your applicationstate
parameter as sent in step 1
Example
GET https://inferno.healthit.gov/suites/custom/smart/redirect?code=FzPDQkGRy0yHttCLo4pFwyCTr-3_aMAjJ8ctngFzoFM&state=42042f18-a66c-4a55-86ca-bf1d72d25798
-
Your application exchanges the authorization token for an access token
Your application will send a
POST
request to thetoken
endpoint with a url-encoded form payload (Content-Type: application/x-www-form-urlencoded
). The parameters sent depend on whether your application was issued a client secret or not:grant_type
- alwaysauthorization_code
redirect_uri
- your application redirect URLcode
- the authorization code received during the previous step
If the application does not own a client secret the the
client_id
parameter is sent in the query string as well.If the application owns a client secret then the
client_id
value is passed to thetoken
endpoint in theAuthorization
header following theBasic
authentication scheme:Authorization: Basic base64Encode{<client_id>:<client_secret>}
The token server responds with a JSON object that includes:
token_type
- alwaysBearer
expires_in
- token expiration time in secondsaccess_token
- the access token granted to your applicationscope
- the scopes consented by the userrefresh_token
- returned only if the application owns a client secret. The refresh token can be used to rquest a new access token after the current access token has expired.id_token
- returned if theopenid
scope was requestedpatient
- thepatient
id for patient facing workflows
Example
Request
POST https://r4cert.medicasoft.us/api/security/smart/token Content-Type: application/x-www-form-urlencoded Authorization: Basic VGVzdENsaWVudElkOlRlc3RDbGllbnRTZWNyZXQK code=FzPDQkGRy0yHttCLo4pFwyCTr-3_aMAjJ8ctngFzoFM&grant_type=authorization_code&redirect_uri=https%3A%2F%2Finferno.healthit. gov%2Fsuites%2Fcustom%2Fsmart%2Fredirect
Response
{ "token_type": "Bearer", "expires_in": 86400, "access_token": "eyJraWQiOiJpLUs5RzVMdl9EOFpfcGZfYTVpeUtaeTVaSkpiM1l6TDJfOUhDOXZTMTdRIiwiYWxnIjoiUlMyNTYifQ. eyJ2ZXIiOjEsImp0aSI6IkFULlg5Q1VsZkRYOUY1TXhsY0tuU0w3bGthMU1zbk5EakdRYVptQnNENC1fTlUub2FycDZ2b3lxOUFTc0llMHQ1ZDYiLCJpc3MiOiJodHRwczovL2Rldi01MzgzNDAwMC5va3RhLm NvbS9vYXV0aDIvYXVzNGlxazFqMjE3N2psOU41ZDciLCJhdWQiOiJodHRwczovL3I0Y2VydC5tZWRpY2Fzb2Z0LnVzL2ZoaXIiLCJpYXQiOjE2NjU4MTY4OTksImV4cCI6MTY2NTkwMzI5OSwiY2lkIjoiMG9h NGlxOXR5djhSYXFEZkc1ZDciLCJ1aWQiOiIwMHU2djFrMHJiSFlHR1F5djVkNyIsInNjcCI6WyJwYXRpZW50L0RvY3VtZW50UmVmZXJlbmNlLnJlYWQiLCJwYXRpZW50L1BhdGllbnQucmVhZCIsIm9wZW5pZC IsInBhdGllbnQvUHJvY2VkdXJlLnJlYWQiLCJwYXRpZW50L09yZ2FuaXphdGlvbi5yZWFkIiwicGF0aWVudC9Mb2NhdGlvbi5yZWFkIiwicGF0aWVudC9NZWRpY2F0aW9uLnJlYWQiLCJwYXRpZW50L0NvbmRp dGlvbi5yZWFkIiwicGF0aWVudC9PYnNlcnZhdGlvbi5yZWFkIiwicGF0aWVudC9EZXZpY2UucmVhZCIsInBhdGllbnQvQ2FyZVRlYW0ucmVhZCIsImZoaXJVc2VyIiwicGF0aWVudC9JbW11bml6YXRpb24ucm VhZCIsImxhdW5jaC9wYXRpZW50IiwicGF0aWVudC9QcmFjdGl0aW9uZXIucmVhZCIsInBhdGllbnQvUHJvdmVuYW5jZS5yZWFkIiwicGF0aWVudC9Hb2FsLnJlYWQiLCJvZmZsaW5lX2FjY2VzcyIsInBhdGll bnQvQ2FyZVBsYW4ucmVhZCIsInBhdGllbnQvRW5jb3VudGVyLnJlYWQiLCJwYXRpZW50L1ByYWN0aXRpb25lclJvbGUucmVhZCIsInBhdGllbnQvQWxsZXJneUludG9sZXJhbmNlLnJlYWQiLCJwYXRpZW50L0 1lZGljYXRpb25SZXF1ZXN0LnJlYWQiLCJwYXRpZW50L0RpYWdub3N0aWNSZXBvcnQucmVhZCJdLCJhdXRoX3RpbWUiOjE2NjU4MTY2NTMsInN1YiI6InBhdGllbnRAbWVkaWNhc29mdC51cyIsImxhdW5jaF9y ZXNwb25zZV9wYXRpZW50IjoiYmNmYTgzZGYtZWU4Yy05NzIxLWNjMDctYmRjZmMyYjFlM2YyIiwidmFsaWRfY29uc2VudCI6InRydWUiLCJmaGlyVXNlciI6IlBhdGllbnQvYmNmYTgzZGYtZWU4Yy05NzIxLW NjMDctYmRjZmMyYjFlM2YyIn0. fqIM8d6UAAczhNlvHrglVkd2_F4eAIVVXAnkAYnITRCTTyo62jLy6gdG46DB5A29tPKHvEhScFCutsnYudMmj8qaCTMZN7OFGC8bSMyZY76xrgYr8Bfgorr-1cDcAbhwu6eACxTCHjJuAUrG2knLam5l7iviCL y31Ua-d2kI0Wm7z1QKGFFGU_bNS229bS09dyHB4Rho1myFTEpninuf1D9Q1Op-J3GSWGGBO5g0XQg3bpyeFPPNNumyRYsfEr7oiPU7lyq17xYaweU_GQgLn3-JSfrmBJ16YPAdbOsw6nvsPxwTjvyVMqHC70tT J_HU2SR_bsGHPf7JaNn_F0FzpQ", "scope": "patient/DocumentReference.read patient/Patient.read openid patient/Procedure.read patient/Organization.read patient/Location.read patient/ Medication.read patient/Condition.read patient/Observation.read patient/Device.read patient/CareTeam.read fhirUser patient/Immunization.read launch/patient patient/Practitioner.read patient/Provenance.read patient/Goal.read offline_access patient/CarePlan.read patient/Encounter.read patient/PractitionerRole.read patient/AllergyIntolerance.read patient/MedicationRequest.read patient/DiagnosticReport.read", "refresh_token": "IMUQELjly8LnHlKrZLgunvmiXu8nfNnmiTlFMOwGEZs", "id_token": "eyJraWQiOiJpLUs5RzVMdl9EOFpfcGZfYTVpeUtaeTVaSkpiM1l6TDJfOUhDOXZTMTdRIiwiYWxnIjoiUlMyNTYifQ. eyJzdWIiOiIwMHU2djFrMHJiSFlHR1F5djVkNyIsInZlciI6MSwiaXNzIjoiaHR0cHM6Ly9kZXYtNTM4MzQwMDAub2t0YS5jb20vb2F1dGgyL2F1czRpcWsxajIxNzdqbDlONWQ3IiwiYXVkIjoiMG9hNGlxOX R5djhSYXFEZkc1ZDciLCJpYXQiOjE2NjU4MTY4OTksImV4cCI6MTY2NTgyMDQ5OSwianRpIjoiSUQuS1hiYno4My1VNDZSRXV6ZWxGM1dpMUtnU2U1bVROcHpuTWlaa1JFOUpaTSIsImFtciI6WyJwd2QiXSwi aWRwIjoiMDBvNGlwbmpteWI0OHU4TEc1ZDciLCJhdXRoX3RpbWUiOjE2NjU4MTY2NTMsImF0X2hhc2giOiJQN0RYUjlHY0c4TURpSmdFLUlvS3lRIiwiZmhpclVzZXIiOiJQYXRpZW50L2JjZmE4M2RmLWVlOG MtOTcyMS1jYzA3LWJkY2ZjMmIxZTNmMiJ9. B0jrd3L0L_7eTh9VvUKs2hoH6stopm0b0fT5Pu_DS3i08gRqH4nEk-usrVEOeq7MxrlzrohKIxqxdQY8M-FrIjVDYKbU2NWwmUacsaC7j7iywQm8yNLN6UsCaJvGOeYgH75SzXBd5pNRunViPZDhyMDnqLSvDL yofXRY23V9yLF7zVlDG-xwRSWT5AvtR6MXw2gWi8owFGD-F_gDTBvtMF7ajStskT3uuCXIRRnktIENBOK7FpvIZ3NJGDRID_5PHmeFPqibI8TrSL98LMpKSJDb_gryyw8NK_KS_iZ_FII02BhvqaczxCw8hzn6 2HIf7MOZPv6lV3oe2H5Z9DHDDQ", "patient": "bcfa83df-ee8c-9721-cc07-bdcfc2b1e3f2" }
-
Your application calls into the FHIR API
The client application can issue FHIR API calls by setting the
Authorization
header with theBearer
scheme and the authorization token received in the previous step.Example
GET https://r4cert.medicasoft.us/api/fhir/Patient?_id=bcfa83df-ee8c-9721-cc07-bdcfc2b1e3f2 Authorization: Bearer eyJraWQiOiJpLUs5RzVMdl9EOFpfcGZfYTVpeUtaeTVaSkpiM1l6TDJfOUhDOXZTMTdRIiwiYWxnIjoiUlMyNTYifQ. eyJ2ZXIiOjEsImp0aSI6IkFULnJQdFBqclpQeTFfbmFLd09yeEdNLUpidjNvUzZVYnVXSDk0N05OSHBnMG8ub2FycDV5ZjRzcmZlSWxVcnc1ZDYiLCJpc3MiOiJodHRwczovL2Rldi01MzgzNDAwMC5va3RhLmNv bS9vYXV0aDIvYXVzNGlxazFqMjE3N2psOU41ZDciLCJhdWQiOiJodHRwczovL3I0Y2VydC5tZWRpY2Fzb2Z0LnVzL2ZoaXIiLCJpYXQiOjE2NjU3NzI1NTEsImV4cCI6MTY2NTg1ODk1MSwiY2lkIjoiMG9hNGlx OXR5djhSYXFEZkc1ZDciLCJ1aWQiOiIwMHU0aXBuanRvRkJxTUhmbjVkNyIsInNjcCI6WyJwYXRpZW50L0RvY3VtZW50UmVmZXJlbmNlLnJlYWQiLCJwYXRpZW50L1BhdGllbnQucmVhZCIsInBhdGllbnQvUHJv Y2VkdXJlLnJlYWQiLCJwYXRpZW50L09yZ2FuaXphdGlvbi5yZWFkIiwicGF0aWVudC9Mb2NhdGlvbi5yZWFkIiwicGF0aWVudC9NZWRpY2F0aW9uLnJlYWQiLCJwYXRpZW50L0NvbmRpdGlvbi5yZWFkIiwicGF0 aWVudC9PYnNlcnZhdGlvbi5yZWFkIiwicGF0aWVudC9EZXZpY2UucmVhZCIsInBhdGllbnQvQ2FyZVRlYW0ucmVhZCIsImZoaXJVc2VyIiwicGF0aWVudC9JbW11bml6YXRpb24ucmVhZCIsImxhdW5jaC9wYXRp ZW50IiwicGF0aWVudC9QcmFjdGl0aW9uZXIucmVhZCIsInBhdGllbnQvUHJvdmVuYW5jZS5yZWFkIiwicGF0aWVudC9Hb2FsLnJlYWQiLCJvcGVuaWQiLCJvZmZsaW5lX2FjY2VzcyIsInBhdGllbnQvQ2FyZVBs YW4ucmVhZCIsInBhdGllbnQvUHJhY3RpdGlvbmVyUm9sZS5yZWFkIiwicGF0aWVudC9FbmNvdW50ZXIucmVhZCIsInBhdGllbnQvQWxsZXJneUludG9sZXJhbmNlLnJlYWQiLCJwYXRpZW50L01lZGljYXRpb25S ZXF1ZXN0LnJlYWQiLCJwYXRpZW50L0RpYWdub3N0aWNSZXBvcnQucmVhZCJdLCJhdXRoX3RpbWUiOjE2NjU3Njk4MTcsInN1YiI6ImNhdGFsaW4uYnJhbmVhQG1lZGljYXNvZnRsbGMuY29tIiwibGF1bmNoX3Jl c3BvbnNlX3BhdGllbnQiOiJiY2ZhODNkZi1lZThjLTk3MjEtY2MwNy1iZGNmYzJiMWUzZjIiLCJ2YWxpZF9jb25zZW50IjoidHJ1ZSIsInBhdGllbnQiOiJiY2ZhODNkZi1lZThjLTk3MjEtY2MwNy1iZGNmYzJi MWUzZjIiLCJmaGlyVXNlciI6IlBhdGllbnQvYmNmYTgzZGYtZWU4Yy05NzIxLWNjMDctYmRjZmMyYjFlM2YyIn0. T9PEjb1c_zBqSAIlcPcAFLAdNdQKuNbOfB0yK28-5PqNJVuauY5q0COqMVqDcvKdsEpBMWcT5HFN5h0i-Lo7D262_KMuYAE2S9PJOcyumfZchYVgqJqErVz-5S8WvWxXPJKV2lEcJA6-8S14vPaxlj_NF9c1X9ZT 8wgjVaN-xvRwWZR_mCQRM6NkK3HlJGA_UEjMb__Oh3Y4U3zR2oTdYQHcbz8NTG-p9TQD5V0xtQChSX1PVTI4MxqOKveSHIJMfHk-JLM5AMw94GAcVs6dPRQivLnsyJ3Ohg2ezc89d6xobuiQ016zls_dRijdvfXr A6y7810RLK__gXntPQsVBQ
-
Your application uses a refresh token to request a new access token
When the
access token
has expired the client application ca use therefresh token
to request a newaccess token
. To do that you have to issue aPOST
request to thetoken
endpoint with a url-encoded form payload (Content-Type: application/x-www-form-urlencoded
) having two parameters:grant_type
- alwaysrefresh_token
refresh_token
- the refresh token received during step 3
The
Authorization
header should be set with theBasic
authentication scheme with theusername
set to theclient_id
andpassword
set to theclient_secret
:Authorization: Basic base64Encode{<client_id>:<client_secret>}
The authorization server will respond with a JSON object similar to the one returned in step 3:
{ "token_type": "Bearer", "expires_in": 86400, "access_token": "eyJraWQiOiJpLUs5RzVMdl9EOFpfcGZfYTVpeUtaeTVaSkpiM1l6TDJfOUhDOXZTMTdRIiwiYWxnIjoiUlMyNTYifQ. eyJ2ZXIiOjEsImp0aSI6IkFULllraERma0d2TWpsbk1pdW5SSXB1LXZjOU5lVzZ0WTN6UmI3eHJEMzd1X0Uub2FycDZ2b3lxOUFTc0llMHQ1ZDYiLCJpc3MiOiJodHRwczovL2Rldi01MzgzNDAwMC5va3RhLm NvbS9vYXV0aDIvYXVzNGlxazFqMjE3N2psOU41ZDciLCJhdWQiOiJodHRwczovL3I0Y2VydC5tZWRpY2Fzb2Z0LnVzL2ZoaXIiLCJpYXQiOjE2NjU4MTY5MDMsImV4cCI6MTY2NTkwMzMwMywiY2lkIjoiMG9h NGlxOXR5djhSYXFEZkc1ZDciLCJ1aWQiOiIwMHU2djFrMHJiSFlHR1F5djVkNyIsInNjcCI6WyJwYXRpZW50L0RvY3VtZW50UmVmZXJlbmNlLnJlYWQiLCJwYXRpZW50L1BhdGllbnQucmVhZCIsIm9wZW5pZC IsInBhdGllbnQvUHJvY2VkdXJlLnJlYWQiLCJwYXRpZW50L09yZ2FuaXphdGlvbi5yZWFkIiwicGF0aWVudC9Mb2NhdGlvbi5yZWFkIiwicGF0aWVudC9NZWRpY2F0aW9uLnJlYWQiLCJwYXRpZW50L0NvbmRp dGlvbi5yZWFkIiwicGF0aWVudC9PYnNlcnZhdGlvbi5yZWFkIiwicGF0aWVudC9EZXZpY2UucmVhZCIsInBhdGllbnQvQ2FyZVRlYW0ucmVhZCIsImZoaXJVc2VyIiwicGF0aWVudC9JbW11bml6YXRpb24ucm VhZCIsImxhdW5jaC9wYXRpZW50IiwicGF0aWVudC9QcmFjdGl0aW9uZXIucmVhZCIsInBhdGllbnQvUHJvdmVuYW5jZS5yZWFkIiwicGF0aWVudC9Hb2FsLnJlYWQiLCJvZmZsaW5lX2FjY2VzcyIsInBhdGll bnQvQ2FyZVBsYW4ucmVhZCIsInBhdGllbnQvUHJhY3RpdGlvbmVyUm9sZS5yZWFkIiwicGF0aWVudC9FbmNvdW50ZXIucmVhZCIsInBhdGllbnQvQWxsZXJneUludG9sZXJhbmNlLnJlYWQiLCJwYXRpZW50L0 1lZGljYXRpb25SZXF1ZXN0LnJlYWQiLCJwYXRpZW50L0RpYWdub3N0aWNSZXBvcnQucmVhZCJdLCJhdXRoX3RpbWUiOjE2NjU4MTY2NTMsInN1YiI6InBhdGllbnRAbWVkaWNhc29mdC51cyIsImxhdW5jaF9y ZXNwb25zZV9wYXRpZW50IjoiYmNmYTgzZGYtZWU4Yy05NzIxLWNjMDctYmRjZmMyYjFlM2YyIiwidmFsaWRfY29uc2VudCI6InRydWUiLCJwYXRpZW50IjoiYmNmYTgzZGYtZWU4Yy05NzIxLWNjMDctYmRjZm MyYjFlM2YyIiwiZmhpclVzZXIiOiJQYXRpZW50L2JjZmE4M2RmLWVlOGMtOTcyMS1jYzA3LWJkY2ZjMmIxZTNmMiJ9. kDeXOTCjQNA8JsySKv3zcBVPPXTsAKUUPFCt4CYtBVsQ3pYgF46n7QLOGUnePxsiBXKewY5iXhIAdcpml7i5edbXWqav-sQ-XG9jZnlPn4AHFlBrAT2CWA2ZiYLuExdB3Ck2vP5XUEb6vDeiDV1NXJdL4M_42X Ywil8BiGdYhZP8stza8kiWJKCAS8h9Svk9phegGqLDY_wEjH8nAHzw0W2-ZJSq85-OpaQusTxn2y65nndTqaKls7ElCHldsnduSG0k_PK8HlPop3vJuJ830hMjR0t7Yro7n8iOToWiMzzsbSLG0RT6qbiE1SxE qOdbmpvyILLWL7uWH8GuffgYkg", "scope": "patient/DocumentReference.read patient/Patient.read openid patient/Procedure.read patient/Organization.read patient/Location.read patient/ Medication.read patient/Condition.read patient/Observation.read patient/Device.read patient/CareTeam.read fhirUser patient/Immunization.read launch/patient patient/Practitioner.read patient/Provenance.read patient/Goal.read offline_access patient/CarePlan.read patient/PractitionerRole.read patient/Encounter.read patient/AllergyIntolerance.read patient/MedicationRequest.read patient/DiagnosticReport.read", "refresh_token": "IMUQELjly8LnHlKrZLgunvmiXu8nfNnmiTlFMOwGEZs", "id_token": "eyJraWQiOiJpLUs5RzVMdl9EOFpfcGZfYTVpeUtaeTVaSkpiM1l6TDJfOUhDOXZTMTdRIiwiYWxnIjoiUlMyNTYifQ. eyJzdWIiOiIwMHU2djFrMHJiSFlHR1F5djVkNyIsInZlciI6MSwiaXNzIjoiaHR0cHM6Ly9kZXYtNTM4MzQwMDAub2t0YS5jb20vb2F1dGgyL2F1czRpcWsxajIxNzdqbDlONWQ3IiwiYXVkIjoiMG9hNGlxOX R5djhSYXFEZkc1ZDciLCJpYXQiOjE2NjU4MTY5MDMsImV4cCI6MTY2NTgyMDUwMywianRpIjoiSUQuVmVFdURueF8ybjZrRXJuRlg5U21oMk1RVENPVmthZ092bllKUENGUDUtTSIsImFtciI6WyJwd2QiXSwi aWRwIjoiMDBvNGlwbmpteWI0OHU4TEc1ZDciLCJhdXRoX3RpbWUiOjE2NjU4MTY2NTMsImF0X2hhc2giOiJGQ1FvRHpvMWtUemg2dDNobE5mckVnIiwiZmhpclVzZXIiOiJQYXRpZW50L2JjZmE4M2RmLWVlOG MtOTcyMS1jYzA3LWJkY2ZjMmIxZTNmMiJ9. ONFVTT19J_HHVd8aayoodzF3sqnG4rGXQJG8ZTqDffL7bTQv9FF3jjCdM7_xxoYQroU355cgxeqyoO8Aky67O4ZG_VANUX-fim1Z8Ie-9KyMvVylnNMZB9ehA5qXb-6bLZy3Sx8VV3DnwnwzLv83uZES0U9Hd1 9GdsfS074woZN65oqxOHjAgeaHi5Zz9bdz6Yie1_Fa-Wu4ce6zwUMGCu68hnGkQpKD6KcI1q4ml92zC2SQ0Sin1Q5hxW516FjVH3wQwM6SC7gZBgvusPc9hlWVh4JRGXuOp5QhyfwMB7Oa-NP8aY9oDOeOLbvY kNeLrbSyjQK8wPO25XcRY4dXRA", "patient": "bcfa83df-ee8c-9721-cc07-bdcfc2b1e3f2" }
System Application authorization flow
A system application pre-authorises it’s users to access FHIR API endpoints. As such it does not need to follow the whole standalone application launch flow. A system application should register a public JWKS endpoint and use the private key authorization flow. To acces the FHIR API the application has to go through the following steps:
-
Your application creates a JWT signed with your private key.
The JWT should contain the following headers:
alg
- should be eitherES384
orRS384
typ
- alwaysJWT
kid
- thekid
value from your public JWKS
The JWT should contain the following claims:
iss
- this is yourclient_id
sub
- this is yourclient_id
aud
- the FHIR endpoint URLexp
- expiration time, should be no more than 5 minutesjti
- a unique identifier for this JWT
-
Your application obtains an access token
The JWT created in step 1 will be sent to the
token
endpoint in aPOST
request. The payload is Form Url-Encoded and it should have the following parameters:grant_type
- alwaysclient_credentials
client_assertion_type
- alwaysurn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_assertion
- the JWT generated in step 1scope
- requested scopes
Example
Request
POST https://dev-53834000.okta.com/oauth2/aus4iqk1j2177jl9N5d7/v1/token Content-Type: application/x-www-form-urlencoded client_assertion=eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzM4NCIsImtpZCI6IjRiNDlhNzM5ZDFlYjExNWIzMjI1ZjRjZjliZWI2ZDFiIn0. eyJpc3MiOiIwb2E2YTRkeWxwZExqbjdhVTVkNyIsInN1YiI6IjBvYTZhNGR5bHBkTGpuN2FVNWQ3IiwiYXVkIjoiaHR0cHM6Ly9kZXYtNTM4MzQwMDAub2t0YS5jb20vb2F1dGgyL2F1czRpcWsxajIxNzdqbDlO NWQ3L3YxL3Rva2VuIiwiZXhwIjoxNjY1NzcyNzk3LCJqdGkiOiI0MTE3YmZmNGQwNjgwYTk4YjU4YTk5ZDc3Zjc3NWNmYjkyMzk1OGRiYjczYjU4YzU4NTNmOTQ0MjkzZjhlNmU2In0. klD80a-HkfZObbe-oZaPWJ02Iv2WaPwU6-nzITg5o4LZO_w6xpZnylZj2LdKekJpDPzQXH8WDitn7Si_8s9SvY6dATEKbekhi2gZe_LtXGoxJSZ7SBtMDP8bmaLnFkPr& client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&grant_type=client_credentials&scope=system%2F%2A.read
Response
{ "token_type": "Bearer", "expires_in": 86400, "access_token": "eyJraWQiOiJpLUs5RzVMdl9EOFpfcGZfYTVpeUtaeTVaSkpiM1l6TDJfOUhDOXZTMTdRIiwiYWxnIjoiUlMyNTYifQ. eyJ2ZXIiOjEsImp0aSI6IkFULkJwZ1JqcmllZUk0aEpSWHMxTHZ4eHhoNTZrNmQtTjk4M1VDT0xJVUtfdXMiLCJpc3MiOiJodHRwczovL2Rldi01MzgzNDAwMC5va3RhLmNvbS9vYXV0aDIvYXVzNGlxazFqMj E3N2psOU41ZDciLCJhdWQiOiJodHRwczovL3I0Y2VydC5tZWRpY2Fzb2Z0LnVzL2ZoaXIiLCJpYXQiOjE2NjU3NzI0OTgsImV4cCI6MTY2NTg1ODg5OCwiY2lkIjoiMG9hNmE0ZHlscGRMam43YVU1ZDciLCJz Y3AiOlsic3lzdGVtLyoucmVhZCJdLCJzdWIiOiIwb2E2YTRkeWxwZExqbjdhVTVkNyIsInZhbGlkX2NvbnNlbnQiOiJ0cnVlIn0. lX8uPwfS149SaxQ6orEtfkLVlv0R_oVn7aeDydjkpx5C5zysiUC5__ETdEGl3cvf5sE-GDBwg-fwUnfKDEJj1XhmW3NZ01G6_NGvEmYzw6UO89djTe07JAqqu1OI6NPkmRHaKsqN_4cNtctWjvlXkZkHbgkYfZ LSZUrE97igNwpcUx2Us29DAZgaTvU5yezM4ZSRKEHupCkBCeP_0Cciq_xQ19vynM46HCfH4T8ckA56BZEcRmb0udRPSj_EnfDH6LVSnPJIKWR3DrwTRe2AneyvAaVkWyw7Ktd3Lif3Jjc_6SbzNI2sep8Tuw3K dGd2XQwJEEgzboZR2jLUzYBKvQ", "scope": "system/*.read" }
Token refresh for native applications
A native application is treated by the NXT platform just as any other public application following the standalone launch sequence. As such in order to request a new access token it will have to present the refresh token
received during step 3 above along with an Authorization
header set with the client_id
and client_secret
(see step 5 above). The native application should take steps to protect the client secret. For best practices please refer to OAuth 2.0 for Mobile and Native Apps.
The NXT FHIR API does not support at this moment the PKCE flow but it makes efforts to provide additional authorization protection in the future.