Authorization


Overview

Cerner’s implementation of the HL7® FHIR® Standard is protected using the SMART® on FHIR® authorization framework. SMART® on FHIR® defines a profile of the OAuth 2 framework for obtaining authorization to act on behalf of users; it is highly recommended that developers review and understand the OAuth 2 framework prior to implementing their authorization workflow. Cerner recommends the following IETF publications for review:

This guide offers:

Benefits of the Authorization Model

The use of an authorization protocol offers additional security for users/enterprises by abstracting the credentials that users use to authenticate to the EHR away from client applications. Under this model, restrictions can be applied to what actions a client application can perform on behalf of the user; this is not possible in traditional models where the application has direct access to the user’s credentials.

Furthermore, by abstracting authentication away from client applications, there is less risk such credentials will be compromised, and organizations have more flexibility in offering differing forms of authentication (possible examples include the use of Windows Hello technology, Apple TouchID, etc.)

Finally, the token model employed by the OAuth 2 authorization framework provides a useful means in a distributed service ecosystem to enforce frequent validation that access has not otherwise been revoked or expired.

A formal technical specification for authorization may be found in the Cerner FHIR® Service Authorization Specification.

Differentiating SMART® and FHIR®

The HL7® FHIR® Standard defines an API to access information within an electronic health record system. The SMART® framework defines an API for applications to obtain an authorized context to access FHIR® resources and exchange context information with client applications.

Registration

In order for your client application to utilize any protected resources, your client application must first be registered. A Cerner Care account is required to register applications. Obtaining a Cerner Care account is free and requires nothing but an email address.

If registering an application that is using the public app profile and requires access only when the user is online, your client application must first register using our code Console.

If you are a Cerner client developing an application, please see this document about how to make your self-developed app available in your domain.

If registering a confidential client application (and/or access on behalf of a system), follow the directions in the Registering a System Account section. Check the respective FHIR® implementation documentation to determine availability.

Once registered, the client identifier will be provided for use with the Cerner Authorization Server. As a registered client, Cerner organizations may then ask for your client application to be enabled, which is necessary in order to gain access to their protected resources.

Registering a System Account

If an application will be a confidential client, or accessing data on behalf of a system, it will need to maintain a secret. Currently, our implementation provides management and rotation functionality for this workflow in our System Accounts application. The system account will be automatically generated and available in the System Accounts application when you register your SMART or FHIR application in the code Console.

Obtain and manage a system account by following these steps:

Remember to protect the secret received via this process. Don’t post this secret or email it in insecure fashion. Don’t include this secret or credentials requests for the authorization server in any posts requesting help. If you do compromise the secret, you can rotate the credentials using the system accounts application above.

Requesting Authorization on Behalf of a User

To access Cerner’s FHIR® services on behalf of a user, your client application must make an authorization request through a user agent on the user’s device. This involves the following steps:

A formal technical specification for this process may be found in the Cerner FHIR® Service Authorization Specification.

Discovering Authorization URLs

Each instance of Cerner’s FHIR® services advertise the URL of its respective authorization server within its FHIR® conformance document.

The FHIR® Conformance resource can be retrieved by performing an HTTP GET against the resource located at the relative path of ./metadata from the FHIR® base URL. Examples of this call can be found on the Conformance documentation for Millennium or Soarian.

Within the structure of this document, three important URLs are advertised in an extension to Conformance.rest.security, identified via the URL of http://fhir-registry.smarthealthit.org/StructureDefinition/oauth-uris.

The first URL is the location of the authorization endpoint, which is further identified by the sub-extension URL “authorize”.

The second URL of importance is the location of the authorization server’s token endpoint, which is further identified by the sub-extension URL “token”.

The third URL of importance is the location of the authorization server’s user-facing authorization management workflow entry point, which is further identified by the sub-extension URL “manage”. This sub-extension is advertised from user-facing instances of Cerner’s FHIR® server.

The following is non-normative example of a conformance document containing this information:

{
  "resourceType": "Conformance",
  "rest": [
    {
      "security": {
        "extension": [
          {
            "url": "http://fhir-registry.smarthealthit.org/StructureDefinition/oauth-uris",
            "extension": [
              {
                "url": "token",
                "valueUri": "https://example.org/token"
              },
              {
                "url": "authorize",
                "valueUri": "https://example.org/authorize"
              },
              {
                "url": "manage",
                "valueUri": "https://example.org/patient/authorizations"
              }
            ]
          }
        ]
      }
    ]
  }
}      

Construct the Authorization Request URL

An authorization request takes the form of an x-www-form-urlencoded query string, appended to the authorization endpoint’s URL (as discovered from the previous section.) The base specification for the structure of this request is defined in section 4.1 “Authorization Code Grant” of RFC6749.

At minimum, the following parameters are included in the authorization request; each are documented in the following sections:

Scopes

During the authorization process, client applications should identify at runtime:

Each of the above pieces of information are presented in the authorization request to the server in the form of “scopes”. Per the OAUTH specification, the scope of a request is “…a list of space-delimited, case-sensitive strings. The strings are defined by the authorization server.” With SMART® on FHIR®, access to FHIR® resources is controlled by scopes with the following format:

scope-name            = resource-context "/" resource-type "." modification-rights
resource-context      = ("user" / "patient" / "system")
resource-type         = (Name)
modification-rights   = ("read" / "write");

Examples of scopes include:

The “resource context” represents one of three possible choices:

In certain cases, the authenticated user will be presented a choice to allow your application to utilize the requested scopes on the user’s behalf. As such, your application should request only the minimum scopes needed in order to fulfill its function.

Note: Many combinations of scopes are possible to be requested and approved, but not all may be recognized by then given version of a FHIR® API resource being used. Please refer to the respective FHIR® API resource documentation for a full list of its capabilities.

In addition to FHIR® resource scopes, the SMART® on FHIR® authorization framework also defines these additional scopes that further govern the behavior of authorization:

Further information on the usage of these special scopes are further detailed below.

Identity Scopes: ‘openid’ and ‘fhirUser’

Certain classes of applications may need to identify the user for whom it is acting on behalf of. Such requirements may include (but are not limited to) the following:

The scope ‘openid’ will request that Cerner’s authorization server supply and OpenID Connect identity token as part of the authorization workflow. Further details on utilizing the OpenID token can be found in the OpenID Connect Guide.

The scope ‘fhirUser’ will additionally request that the OpenID Connect token include the claim ‘fhirUser’, as defined by the SMART® on FHIR® authorization framework. This URL identifies the specific FHIR® resource URL of the authenticated user. This resource may be a Patient, Practitioner, or Person resource, depending on the type of user whom is authenticated.

Duration Scopes: ‘online_access’ and ‘offline_access’

The default duration of access received through the authorization grant workflow is a single token that is valid for 570 seconds (~10 minutes). For applications that need access to services for longer durations, Cerner’s Ignite platform supports the concept of “refresh tokens”.

With ‘online_access’, your application can continue to obtain access tokens on behalf of the user until:

With ‘offline_access’, an application can continue to obtain access tokens in perpetuity on behalf of the user until:

Supported Scopes

Wildcard Scopes are currently not supported; refer to the linked document for a more detailed discussion of the challenges they pose. An application is currently required to specifically request each scope that it needs to run.

Other combinations of scopes may be limited; please see the FAQ for known limitations.

State

When performing an authorization grant request, it is highly recommended that your client application establish a transient, one-time-use “state” value for each individual request you send. If your application receives an authorization response that does not include a value known to the current user’s device, it should reject the response. This mechanism is to protect your application against “cross-site request forgery” classes of exploits. For more information on these types of exploits, consult the RFC OAuth 2.0 Threat Model and Security Considerations.

Audience

When performing an authorization grant request, it is required your client application send the base URL of the FHIR® resource server for which you will be sending access tokens to. This is conveyed via an additional query parameter in the grant request named “aud”. This parameter is utilized by Cerner’s authorization server to protect your application against a form of exploit where an untrusted resource server advertises a legitimate authorization server in its conformance document. Without this feature, a valid, authorized access token could be inadvertently be sent by your application to the untrusted party.

Authorization grant requests that do not contain the audience parameter are automatically rejected by Cerner’s authorization server. The following is a fragment from a x-www-form-urlencoded grant request query string where the audience is provided:

&aud=https%3A%2F%2Ffhir-ehr-code.cerner.com%2Fdstu2%2Fec2458f2-1e24-41c8-b71b-0e701af7583d%2F

Redirect URI

When performing an authorization grant request the application may provide a redirect_uri. This uri should match the redirect_uri setup during the registration phase of the SMART Application.

If your application has multiple redirect_uri’s registered with Cerner then a redirect_uri is expected to be passed in during the authorization grant request. If no redirect_uri is specified the default redirect_uri registered for the application will be used.

Details around supplying a redirect_uri are specified in the SMART Specification

The redirect_uri must be an absolute uri. For more information please consult the Ref : RFC 6749 Redirection Endpoint

Following is a fragment from a x-www-form-urlencoded grant request query string where the redirect_uri is provided:

&redirect_uri=https%3A%2F%2Fapp%2Fafter-auth

A detailed example of an authorization grant request can be found SMART App Launch Example

Launch

Some Cerner solutions support the “launch” feature of the SMART® on FHIR® authorization framework. This feature provides three benefits to client applications:

Examples

The following are hypothetical examples of authorization requests:

client id:    bb318a62-fa61-49ae-b692-7d99214f0ec7
scopes:       patient/Observation.read patient/MedicationHistory.read launch
audience:     https://fhir-ehr-code.cerner.com/dstu2/ec2458f2-1e24-41c8-b71b-0e701af7583d/
state:        a4c16a46-2c46-482c-8d66-4cc4a2990bda
launch:       a17aba51-1395-48d3-b3a9-73f2baf784da

https://authorization.cerner.com/tenants/ec2458f2-1e24-41c8-b71b-0e701af7583d/protocols/oauth2/profiles/smart-v1/personas/patient/authorize?client_id=bb318a62-fa61-49ae-b692-7d99214f0ec7&response_type=code&redirect_uri=&scope=patient%2FObservation.read%20patient%2FMedicationHistory.read%20launch&launch=a17aba51-1395-48d3-b3a9-73f2baf784da&aud=https%3A%2F%2Ffhir-ehr-code.cerner.com%2Fdstu2%2Fec2458f2-1e24-41c8-b71b-0e701af7583d%2F&state=a4c16a46-2c46-482c-8d66-4cc4a2990bda
client id:    bb318a62-fa61-49ae-b692-7d99214f0ec7
scopes:       user/Observation.read user/MedicationHistory.read
audience:     https://fhir-ehr-code.cerner.com/dstu2/ec2458f2-1e24-41c8-b71b-0e701af7583d/
state:        a4c16a46-2c46-482c-8d66-4cc4a2990bda

https://authorization.cerner.com/tenants/ec2458f2-1e24-41c8-b71b-0e701af7583d/protocols/oauth2/profiles/smart-v1/personas/patient/authorize?client_id=bb318a62-fa61-49ae-b692-7d99214f0ec7&response_type=code&redirect_uri=&scope=user%2FObservation.read%20user%2FMedicationHistory.read%20&launch=&aud=https%3A%2F%2Ffhir-ehr-code.cerner.com%2Fdstu2%2Fec2458f2-1e24-41c8-b71b-0e701af7583d%2F&state=a4c16a46-2c46-482c-8d66-4cc4a2990bda

Invoking an Appropriate User Agent

Once an authorization code grant request URL has been generated, you will need to invoke an appropriate user agent to invoke the authorization request. In all scenarios, this web page will interact with the user agent in order to determine the identity of the user. This process may involve further redirects to other identity providers (web applications designed to authenticate users), interaction with browser Javascript APIs, or direct interactions with the end user to obtain their approval during the authorization process.

This particular part of the process has a number of complexities; the recommendations offered in this section are designed to ensure:

The following sections discuss how to invoke the proper user agent for specific platforms.

(Web) Client Applications Delivered via the Browser

For applications delivered via the “https” scheme within a browser, it is recommended to invoke the authorization workflow within a separate pop-up window (for desktops) or tab (for mobile browsers). The use of a pop-up / separate tab ensures that any navigation that occurs while servicing the authentication or authorization workflows are maintained separately from your initial tab, thus allowing the user to properly navigate backwards in their browser history once the authorization workflow has completed. On desktop platforms and/or mobile platforms that offer split-screen browsing, this methodology creates a clean delineation between your application’s workflow and the authorization workflow.

Due to the nature of built-in pop-up blocking functionality, it will generally be necessary for your application to trigger the opening of the window based on a user interaction (click or touch). In certain specific venues, alternatives may be possible to avoid this requirement; further guidance is outside the scope of this guide.

Web-based applications must not attempt to perform the authorization workflow within an iframe - doing so may have unexpected results caused by clickjacking protection mechanisms, anti-phishing protection mechanisms, browser third-party cookie policy, etc.

When opening the additional browser window, it is recommended to include the location “chrome” of the browser such that TLS/EVSSL indicators are included for display to the user. Such visual cues are an important part of security for some authentication systems.

Your authorization response comes in the form of a redirect (which is orchestrated within the child window) to your registered redirect URI. Once your server has processed the response, Javascript can be utilized to notify the parent window that the workflow is complete; in turn, the parent window can close the child window.

Example Javascript for Opening the Authorization Workflow

The below Javascript demonstates how an application could open the authorization workflow as a modal on desktop platforms. In addition to desktop platforms, this method automatically will function on mobile platforms by creating an additional tab or split-screen browsing windows.

var width = 780,
    height = 550,
    left = (screen.width - width) / 2,
    top = (screen.height - height) / 2,
    uniqueWindowId = "authorization-" + yourAppClientId
    params,
    location;
if (top > 20) {
	top = top - 20;
}
params = 'width=' + width + ', height=' + height;
params += ', top=' + top + ', left=' + left;
params += 'titlebar=no, location=yes';
location = build_oauth_request_url();
loginWindow = window.open(location, uniqueWindowId, params);

The following Javascript snippets demonstrate how your application can notify the parent window of the completion of the workflow.

This first script allows your main window to listen to postMessage calls from child windows:

window.addEventListener("message", function (e) {
	var oauthMessage = e.data;
	loginWindow.close();
	processOAuthMessage(oauthMessage);
}, false);

The second script is served by the webpage at your callback URI:

window.opener.postMessage(oauthMessage, 'https://example.com/');

The contents of the “oauthMessage” could be the entirety of the query string, or could be the result of any server-side processing handled by your server as a result of the HTTP GET to the callback URI.

Other User Experience Considerations

Native Client Applications

In recent years, OS platforms have been forced to lock down certain behaviors within their browsers that were traditionally used to facilitate OAuth2-based authorization workflows. Specifically, browsers now interrupt any attempt to direct a user to a native application due to abuse from advertisers of mobile apps. As a result, OS platforms now offer “in-app” browsers useful for orchestrating authorization workflows that are free of such impediments. These “in-app” browsers also improve on the user experience of OAuth2-based workflows by preventing remnant browser tabs and smoothing the transition between browser and app (no OS app switching occurs.)

Refresh tokens for native applications are handled in the same fashion as for web-based applications; see further below for a detailed discussion of this topic.

For more information on best practices for OAuth2-based workflows for native applications, please refer to the IETF Best Current Practices (BCP) “OAuth 2.0 for Native Apps”.

NOTE: Cerner’s Authorization Server does not currently implement PKCE as noted in section 8.2 of the native applications BCP.

The next sections discuss specific special cases not covered by the OAuth native application BCP guide.

“Win32” Applications

Cerner currently supports only explicit internet hosts or explicit URI activation schemes for redirection URIs; as such, developers of traditional Windows applications should register a scheme for their application. The following is a sample registry file for a hypothetical scheme registration of sample.application://:

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\sample.application]
@="URL:Sample Authorization App"
"URL Protocol"=""
"UseOriginalUrlEncoding"="1"

[HKEY_CLASSES_ROOT\sample.application\DefaultIcon]
@="sample.exe,1"

[HKEY_CLASSES_ROOT\sample.application\shell]

[HKEY_CLASSES_ROOT\sample.application\shell\open]

[HKEY_CLASSES_ROOT\sample.application\shell\open\command]
@="c:\\sample.exe \"%1\""

For the above registration, the client application would be registered with a redirection URI whose scheme begins with sample.application://, for example sample.application://callback.
Upon redirection to this scheme, the Windows operating system will invoke the registered application with the OAuth2 response URI passed as the first argument. The client application may then parse the URI and in turn determine which open instance of the application (if multiples are allowed) initiated the equest via examination of the “state” parameter.

Additional registry settings may be required as browser vendors implement mitigations for so-called “scheme flooding” vulnerabilities. For recent versions of Microsoft Edge (for example), the relevant registry settings are AutoLaunchProtocolsComponentEnabled, AutoLaunchProtocolsFromOrigins, and DoNotSilentlyBlockProtocolsFromOrigins. Without these settings, the browser may log errors to the console such as Not allowed to launch <your application scheme> because a user gesture is required. Refer to Microsoft’s documentation for further details.

Processing the Authorization Grant Response

The authorization grant response comes in the form of a x-www-form-urlencoded query string, appended to your redirection URI. The base specification for the structure of this response is defined in section 4.1 “Authorization Code Grant” of RFC6749 (the OAuth2 Framework). The following is an example:

https://example.com/callback?code=0c8b259b-d716-4712-ad6a-1d22d92523fa&state=a4c16a46-2c46-482c-8d66-4cc4a2990bda

Within a successful response, a “code” parameter will be present, and a “state” parameter will be present if your application included “state” as part of the initial request.

First, validate that the “state” parameter matches that of a request that was initiated by the current device / user agent.

Next, exchange the code for a token per section 4.1.3 “Access Token Request” of the RFC6749 (the OAuth2 Framework).

NOTE: If the “redirect_uri” parameter was not provided during the authorization request, the “redirect_uri” must be omitted in the token request call. Otherwise, if “redirect_uri” parameter was provided in the authorization request as described in section 4.1 “Authorization Code Grant”, this also must be present in the token request and their values MUST be identical.

The following are example requests / responses:

Request:

POST /tenants/ec2458f2-1e24-41c8-b71b-0e701af7583d/protocols/oauth2/profiles/smart-v1/token HTTP/1.1
Host: authorization.cerner.com
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Content-Length: 161
Connection: close
grant_type=authorization_code&code=0c8b259b-d716-4712-ad6a-1d22d92523fa&redirect_uri=&client_id=bb318a62-fa61-49ae-b692-7d99214f0ec7

Response:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: OPTIONS, POST
Access-Control-Allow-Headers: Content-Type, Authorization
Cache-Control: no-store
Pragma: no-cache
Content-Type: application/json
Content-Length: 1462
Date: Tue, 01 Nov 2016 19:20:25 GMT

{
  "access_token": "eyJraWQiOiIyMDIwLTA3LTI4VDE3OjM2OjA5LjAwNC5lYyIsInR5cCI6IkpXVCIsImFsZyI6IkVTMjU2In0.eyJzdWIiOiJwb3J0YWwiLCJ1cm46Y29tOmNlcm5lcjphdXRob3JpemF0aW9uOmNsYWltcyI6eyJ2ZXIiOiIxLjAiLCJ0bnQiOiJlYzI0NThmMi0xZTI0LTQxYzgtYjcxYi0wZTcwMWFmNzU4M2QiLCJhenMiOiJ1c2VyXC9PYnNlcnZhdGlvbi5yZWFkIn0sImF6cCI6ImZoaXItbG9jYWwiLCJpc3MiOiJodHRwczpcL1wvYXV0aG9yaXphdGlvbi5jZXJuZXIuY29tXC8iLCJleHAiOjE1OTYwNTYwNjEsImlhdCI6MTU5NjA1NTQ2MSwianRpIjoiYmMwMzIwYTMtN2E3Yi00MmVkLTgzZDAtMWMxMTVlMjBkMDQzIiwidXJuOmNlcm5lcjphdXRob3JpemF0aW9uOmNsYWltczp2ZXJzaW9uOjEiOnsidmVyIjoiMS4wIiwicHJvZmlsZXMiOnsic21hcnQtdjEiOnsiYXpzIjoidXNlclwvT2JzZXJ2YXRpb24ucmVhZCJ9fSwiY2xpZW50Ijp7Im5hbWUiOiJGSElSIExvY2FsIFRlc3QgQ2xpZW50IiwiaWQiOiJmaGlyLWxvY2FsIn0sInVzZXIiOnsicHJpbmNpcGFsIjoicG9ydGFsIiwicGVyc29uYSI6InByb3ZpZGVyIiwiaWRzcCI6ImVjMjQ1OGYyLTFlMjQtNDFjOC1iNzFiLTBlNzAxYWY3NTgzZCIsInNlc3Npb25JZCI6IjFiYmEyOGQ0LTUwM2YtNDgyNi04OTE3LTJhOTIzMzczZjE2YyIsInByaW5jaXBhbFR5cGUiOiJ1c2VybmFtZSIsInByaW5jaXBhbFVyaSI6Imh0dHBzOlwvXC9taWxsZW5uaWEuY2VybmVyLmNvbVwvaW5zdGFuY2VcL2VjMjQ1OGYyLTFlMjQtNDFjOC1iNzFiLTBlNzAxYWY3NTgzZFwvcHJpbmNpcGFsXC8wMDAwLjAwMDAuMDBDMi42REI1IiwiaWRzcFVyaSI6Imh0dHBzOlwvXC9taWxsZW5uaWEuY2VybmVyLmNvbVwvYWNjb3VudHNcL2MxOTQxLmNlcm5fYWJjbi5jZXJuZXJhc3AuY29tXC9lYzI0NThmMi0xZTI0LTQxYzgtYjcxYi0wZTcwMWFmNzU4M2RcL2xvZ2luIn0sInRlbmFudCI6ImVjMjQ1OGYyLTFlMjQtNDFjOC1iNzFiLTBlNzAxYWY3NTgzZCJ9fQ.AruMhr4eaG3QHb794wzavhcD8NQAnao5sZWAe4cFbX4-oSd3pUwomoZ-zR8stSKhnaodS0l5bKGkd72goX0PNQ", 
  "scope": "user/Observation.read",
  "token_type": "Bearer",
  "expires_in": 570
}

Three elements of the response should be evaluated:

The following additional elements may be returned:

Closing the Grant Interaction

Once the authorization grant response has been received, the separate window / user agent for the facilitating the grant interaction should be automatically closed, where possible (an example of this for web-based applications is included earlier in this document.) In the event this step is either not successful or not possible, content is provided by the authorization server to inform the user if it is safe to close the additional window. The authorization server itself will not attempt to self-close the window, as this generally results in a prompt from the browser asking for permission.

Exception Handling

Both the authorization grant response and access token response can result in errors. The following is an example error response from the grant workflow:

https://example.com/callback?state=f09dcfff-95ff-4e86-a689-05c8dd9719a2&error=access_denied&error_uri=https%3A%2F%2Fauthorization.cerner.com%2Ferrors%2Furn%253Acerner%253Aerror%253Aauthorization-server%253Aoauth2%253Agrant%253Adenied-by-server%2Finstances%2F42925fc9-7a7e-4cb0-95e4-4d3f178f68b7%3Fpersona%3Dprovider%26client%3Ddevjs%26tenant%3Dec2458f2-1e24-41c8-b71b-0e701af7583d

The following is an example error response from an access token request:

{
  "error": "invalid_grant",
  "error_uri": "https://authorization.cerner.com/errors/urn%3Acerner%3Aerror%3Aauthorization-server%3Aoauth2%3Atoken%3Acode-invalid-or-expired/instances/6359728c-c966-4929-bbf6-2388d353d89e?client=devjs&tenant=ec2458f2-1e24-41c8-b71b-0e701af7583d"
}

In either circumstance, Cerner’s authorization server communicates the parameter error_uri, which represents a URI that contains additional information useful for end users, client app developers, and support personnel, along with support contact information for the associated organization. It is recommended when such errors occur to present a “more information” link or button to the user (hyperlinked to the value of the URI) in addition to other support instructions that your application displays to the user. Furthermore, it may be prudent for your application to display a “retry” or “start over” mechanism such that the user can retry the operation once the problem has been corrected.

Utilizing Refresh Tokens

If your application is designed to interact with a user over periods of time longer than that of a single access token, it will be necessary to utilize “refresh” tokens. A refresh token is an additional secret value, returned as part of the initial access token response, that can be used to obtain additional access tokens. Two forms of access exist, each are requested as a special scope in the authorization grant request:

As access tokens are valid for periods that are less than ten minutes, it is recommended to retrieve and cache new tokens in advance of the previous token expiring. Doing so out-of-band of a user interaction will reduce the user’s perception of application latency. Refresh attempts at intervals lower than one minute may result in throttling. It is not recommended to utilize tokens that are near the precipice of expiry as latency could result in token rejection.

Access Token Request / Response

The following are examples of the request/response mechanism defined in section 6 “Refreshing an Access Token” of the OAuth2 Framework.

Request:

POST /tenants/ec2458f2-1e24-41c8-b71b-0e701af7583d/protocols/oauth2/profiles/smart-v1/token HTTP/1.1
Host: authorization.cerner.com
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Content-Length: 75
Connection: close

grant_type=refresh_token&refresh_token=b30911a8-9278-45aa-bbd9-aa05244faf3b

Response:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: OPTIONS, POST
Access-Control-Allow-Headers: Content-Type, Authorization
Cache-Control: no-store
Pragma: no-cache
Content-Type: application/json
Content-Length: 1514
Date: Tue, 01 Nov 2016 20:48:32 GMT

{
  "access_token": "eyJraWQiOiIyMDIwLTA3LTI4VDE3OjM2OjA5LjAwNC5lYyIsInR5cCI6IkpXVCIsImFsZyI6IkVTMjU2In0.eyJzdWIiOiJwb3J0YWwiLCJ1cm46Y29tOmNlcm5lcjphdXRob3JpemF0aW9uOmNsYWltcyI6eyJ2ZXIiOiIxLjAiLCJ0bnQiOiJlYzI0NThmMi0xZTI0LTQxYzgtYjcxYi0wZTcwMWFmNzU4M2QiLCJhenMiOiJvbmxpbmVfYWNjZXNzIHVzZXJcL09ic2VydmF0aW9uLnJlYWQifSwiYXpwIjoiZmhpci1sb2NhbCIsImlzcyI6Imh0dHBzOlwvXC9hdXRob3JpemF0aW9uLmNlcm5lci5jb21cLyIsImV4cCI6MTU5NjA1NjIyOCwiaWF0IjoxNTk2MDU1NjI4LCJqdGkiOiI4YzdjNDBlMy00NDA0LTQ4MmMtYjY2MC0xOTFhNWQ1M2ViNjAiLCJ1cm46Y2VybmVyOmF1dGhvcml6YXRpb246Y2xhaW1zOnZlcnNpb246MSI6eyJ2ZXIiOiIxLjAiLCJwcm9maWxlcyI6eyJzbWFydC12MSI6eyJhenMiOiJvbmxpbmVfYWNjZXNzIHVzZXJcL09ic2VydmF0aW9uLnJlYWQifX0sImNsaWVudCI6eyJuYW1lIjoiRkhJUiBMb2NhbCBUZXN0IENsaWVudCIsImlkIjoiZmhpci1sb2NhbCJ9LCJ1c2VyIjp7InByaW5jaXBhbCI6InBvcnRhbCIsInBlcnNvbmEiOiJwcm92aWRlciIsImlkc3AiOiJlYzI0NThmMi0xZTI0LTQxYzgtYjcxYi0wZTcwMWFmNzU4M2QiLCJzZXNzaW9uSWQiOiIxYmJhMjhkNC01MDNmLTQ4MjYtODkxNy0yYTkyMzM3M2YxNmMiLCJwcmluY2lwYWxUeXBlIjoidXNlcm5hbWUiLCJwcmluY2lwYWxVcmkiOiJodHRwczpcL1wvbWlsbGVubmlhLmNlcm5lci5jb21cL2luc3RhbmNlXC9lYzI0NThmMi0xZTI0LTQxYzgtYjcxYi0wZTcwMWFmNzU4M2RcL3ByaW5jaXBhbFwvMDAwMC4wMDAwLjAwQzIuNkRCNSIsImlkc3BVcmkiOiJodHRwczpcL1wvbWlsbGVubmlhLmNlcm5lci5jb21cL2FjY291bnRzXC9jMTk0MS5jZXJuX2FiY24uY2VybmVyYXNwLmNvbVwvZWMyNDU4ZjItMWUyNC00MWM4LWI3MWItMGU3MDFhZjc1ODNkXC9sb2dpbiJ9LCJ0ZW5hbnQiOiJlYzI0NThmMi0xZTI0LTQxYzgtYjcxYi0wZTcwMWFmNzU4M2QifX0.e0fhw5QGS_Nf2GQw5zdPOr79j-NQkk5pWQKuvXgo_jMW3Nwqi47KKrMF2eUkAtf9-_hyHEU_R6Ri8Je5FRfjoA",
  "scope": "user/Observation.read online_access",
  "token_type": "Bearer",
  "expires_in": 570
}

NOTE: The token response from a refresh will not contain a new refresh token. The original refresh token from the initial grant response must be retained.

Considerations for Handling ‘online_access’

When retrieving an access token utilizing using an online_access refresh, the most likely cause of failures is that the user’s session has been terminated. The following steps are recommended for the user experience:

Considerations for Handling ‘offline_access’

Cerner’s authorization server can be used as an authentication mechanism via the use of the “openid” scope. In this scenario, an offline access refresh token could be stored in your application’s service tier and associated with the user’s OpenID Connect principal and issuer. Upon subsequent access, the client application would invoke an authorization request containing the “openid” scope to solely perform authentication to allow your service tier to identify the user and any refresh tokens your application currently possesses for the user.

NOTE: Cerner’s authorization server currently does not support the stand-alone “openid” workflow for patients and/or their authorized representatives.

When retrieving an access token utilizing using an offline_access refresh, the most likely cause of failures is that access has been suspended or completely revoked. The following steps are recommended for the user experience:

NOTE: The authorization server will not explicitly indicate whether a token was revoked or suspended. As a result, there are additional recommendations to improve the overall interaction with the end-user as described below.

The error_uri used in the hyperlink/button should be launched in a separate browser window/tab. This is recommended because there is no callback/redirect mechanism to get the user back into the application once they take an action and the error_uri will only provide an opportunity for the user to re-approve the application if it was temporarily suspended.

Additionally, your application should provide a modal dialog to prompt the user for an action that coincides with their choice and/or action in the separate window. This should include options to retry the token refresh, request an entirely new authorization grant, and simply stop using the application (and log out if necessary).

Note that the automatic suspension of a token can occur when the TLS or DNS information has changed since the original authorization. For example, if your application’s TLS certificate has expired, then your application’s refresh token will be suspended. See the Application Registration Prerequisites for additional information about TLS and DNS requirements.

Utilizing Authorization

To utilize access Cerner FHIR® resources utilizing an access token, include a “bearer” authorization header in your HTTP request per RFC 6750 as follows:

Authorization: Bearer eyJraWQiOiIyMDIwLTA3LTI4VDE3OjM2OjA5LjAwNC5lYyIsInR5cCI6IkpXVCIsImFsZyI6IkVTMjU2In0.eyJzdWIiOiJwb3J0YWwiLCJ1cm46Y29tOmNlcm5lcjphdXRob3JpemF0aW9uOmNsYWltcyI6eyJ2ZXIiOiIxLjAiLCJ0bnQiOiJlYzI0NThmMi0xZTI0LTQxYzgtYjcxYi0wZTcwMWFmNzU4M2QiLCJhenMiOiJvbmxpbmVfYWNjZXNzIHVzZXJcL09ic2VydmF0aW9uLnJlYWQifSwiYXpwIjoiZmhpci1sb2NhbCIsImlzcyI6Imh0dHBzOlwvXC9hdXRob3JpemF0aW9uLmNlcm5lci5jb21cLyIsImV4cCI6MTU5NjA1NjIyOCwiaWF0IjoxNTk2MDU1NjI4LCJqdGkiOiI4YzdjNDBlMy00NDA0LTQ4MmMtYjY2MC0xOTFhNWQ1M2ViNjAiLCJ1cm46Y2VybmVyOmF1dGhvcml6YXRpb246Y2xhaW1zOnZlcnNpb246MSI6eyJ2ZXIiOiIxLjAiLCJwcm9maWxlcyI6eyJzbWFydC12MSI6eyJhenMiOiJvbmxpbmVfYWNjZXNzIHVzZXJcL09ic2VydmF0aW9uLnJlYWQifX0sImNsaWVudCI6eyJuYW1lIjoiRkhJUiBMb2NhbCBUZXN0IENsaWVudCIsImlkIjoiZmhpci1sb2NhbCJ9LCJ1c2VyIjp7InByaW5jaXBhbCI6InBvcnRhbCIsInBlcnNvbmEiOiJwcm92aWRlciIsImlkc3AiOiJlYzI0NThmMi0xZTI0LTQxYzgtYjcxYi0wZTcwMWFmNzU4M2QiLCJzZXNzaW9uSWQiOiIxYmJhMjhkNC01MDNmLTQ4MjYtODkxNy0yYTkyMzM3M2YxNmMiLCJwcmluY2lwYWxUeXBlIjoidXNlcm5hbWUiLCJwcmluY2lwYWxVcmkiOiJodHRwczpcL1wvbWlsbGVubmlhLmNlcm5lci5jb21cL2luc3RhbmNlXC9lYzI0NThmMi0xZTI0LTQxYzgtYjcxYi0wZTcwMWFmNzU4M2RcL3ByaW5jaXBhbFwvMDAwMC4wMDAwLjAwQzIuNkRCNSIsImlkc3BVcmkiOiJodHRwczpcL1wvbWlsbGVubmlhLmNlcm5lci5jb21cL2FjY291bnRzXC9jMTk0MS5jZXJuX2FiY24uY2VybmVyYXNwLmNvbVwvZWMyNDU4ZjItMWUyNC00MWM4LWI3MWItMGU3MDFhZjc1ODNkXC9sb2dpbiJ9LCJ0ZW5hbnQiOiJlYzI0NThmMi0xZTI0LTQxYzgtYjcxYi0wZTcwMWFmNzU4M2QifX0.e0fhw5QGS_Nf2GQw5zdPOr79j-NQkk5pWQKuvXgo_jMW3Nwqi47KKrMF2eUkAtf9-_hyHEU_R6Ri8Je5FRfjoA

If the access token is invalid, the FHIR® resource will return a “WWW-Authenticate” header in the response with additional details per RFC 6750.

User Experience

The next sections include user experience recommendations your application should consider/incorporate in its design.

Handling the Authorization Request Window Being Closed

When presenting an authorization request to the user, the possibility exists that the user might simply close the window. This could occur as a result of the user choosing not to accept the terms, or could occur due to a failure to display the content.

In this scenario, your application should check and detect if the window has closed, and react accordingly. Offer the ability for the user to try again or to cancel, and explain any consequences of cancelling.

If your application is interactive and utilizes “online_access” or “offline_access”, it should present a link to the end user that allows the user to manage their current authorizations. Generally, such links are presented in conjunction with menu accessible from a status bar.

For information on how to discover the management endpoint for a user, see Discovery in the authorization specification.

Requesting Authorization on Behalf of a System

Certain types of applications and automated processes do not act on behalf of end users. Such access is generally utilized by a covered entity itself, or another entity covered under a business associate agreement.

Some FHIR® APIs support this model, allowing a client application to directly authenticate for access using a system account issued via Cerner Central System Account Management. See the Registering a System Account section for more information on how to register these applications.

Note: This access model is only supported on resources where explicitly indicated in their respective FHIR® API resource documentation.

Basic Authentication

A client performs this request utilizing the “client credentials” flow of OAuth2 to request an access token, using the Basic authentication scheme for passing credentials. The credentials to use to perform this request will be based on the system account.

The access token should be created using the system account’s id and secret, and encoded using the Base64 encoding scheme. Then, it can be used as the Basic Authorization for a request. The following is an example of an access token using the Basic authentication scheme:

System account id / Client id: bb318a62-fa61-49ae-b692-7d99214f0ec7
Secret: secret

Base64 encode "clientid:secret":
"bb318a62-fa61-49ae-b692-7d99214f0ec7:secret" => YmIzMThhNjItZmE2MS00OWFlLWI2OTItN2Q5OTIxNGYwZWM3OnNlY3JldA==

Use this value in Authorization header:
Authorization: Basic YmIzMThhNjItZmE2MS00OWFlLWI2OTItN2Q5OTIxNGYwZWM3OnNlY3JldA==

The following is a non-normative example of a request made using the system account credentials:

Request:

POST /tenants/ec2458f2-1e24-41c8-b71b-0e701af7583d/protocols/oauth2/profiles/smart-v1/token HTTP/1.1
Host: authorization.cerner.com
Authorization: Basic YmIzMThhNjItZmE2MS00OWFlLWI2OTItN2Q5OTIxNGYwZWM3OnNlY3JldA==
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Content-Length: 61
Connection: close
grant_type=client_credentials&scope=system%2FObservation.read%20system%2FPatient.read

As an example, here is how the token may be requested via cURL:

export SYSTEM_ACCOUNT_CLIENT_ID="bb318a62-fa61-49ae-b692-7d99214f0ec7"
export SYSTEM_ACCOUNT_CLIENT_SECRET="secret"

curl -X POST 'https://authorization.cerner.com/tenants/ec2458f2-1e24-41c8-b71b-0e701af7583d/protocols/oauth2/profiles/smart-v1/token' \
  -H 'Accept: application/json' \
  -H "Authorization: Basic $(echo -n $SYSTEM_ACCOUNT_CLIENT_ID:$SYSTEM_ACCOUNT_CLIENT_SECRET | base64)" \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -H 'cache-control: no-cache' \
  -d 'grant_type=client_credentials&scope=system%2FObservation.read%20system%2FPatient.read'

JWT Authentication

Alternatively, clients may authenticate themselves using signed JSON Web Tokens (JWTs). This is the preferred mode of authentication for Bulk Data clients. For complete details, see SMART App Launch: Backend Services.

Note that clients leveraging this type of authentication must also pre-register their JSON Web Key Sets (JWKS) using Cerner Central System Account Management. For complete details, see Managing JSON Web Key Sets in System Account Management.

Frequently Asked Questions

The next sections discuss questions that application developers may pose that are not covered by the preceding documentation.

How can I allow users to utilize devices that do not provide a browser (user agent) to facilitate the authorization workflow?

Cerner currently does not have a mechanism to allow such devices to participate in the authorization ecosystem.

What happens when a user revokes my application’s access to their data?

When a user revokes an application’s access, its refresh tokens immediately become non-functional. Access tokens cannot be directly revoked; however, they are only valid for a brief period in any case (on the order of a few minutes). As a result, it is generally unnecessary (and inefficient) for applications to check for access token validity using an introspection endpoint. This behavior is discussed in more detail in Section 3 of RFC 7009 “OAuth 2.0 Token Revocation”, as well as Section 16.18 of the “OpenID Connect Core 1.0” specification.

What happens if a refresh token is suspended?

When the authorization server suspends a refresh token, the user can re-approve the application so that a subsequent token refresh will succeed. The application must present the error_uri link to the user so that they can launch the management application to re-approve the token. However, if the user does not do this, or they deny the re-approval, then the token refresh will continue to fail. As an alternative, the application can request an entirely new token via a new authorization grant request.

How can my application revoke a refresh token on behalf of a user?

The location of an RFC 7009 token revocation endpoint is advertised at /.well-known/smart-configuration; see CapabilityStatement for further details.

How can my application participate in log out mechanisms provided by the organization’s single sign-on (SSO) ecosystem?

While the Cerner authorization server provides OpenID Connect support, it does not currently implement any of OpenID Connect’s various logout specifications, nor are they required by the SMART specifications at this time.

As an alternative, you may offer the user a link to “Manage Authorized Applications”, which allows the user to log out via their SSO system.

A browser window/tab remains after the completion of the authorization workflow. How should my application handle this?

Depending on how the browser was launched, your application may not have the ability to close the browser window. If you launched a fresh browser window directly, you may be able to use Windows APIs to find and send a close command directly to the window.

Does the Cerner authorization server offer an authentication-only workflow (via OpenID Connect) for patients and/or their authorized representatives?

Cerner currently does not offer this capability at this time.

Can I append additional query parameters for my redirection URI when I send my authorization grant request?

Yes, Cerner’s redirection URI validation allows for additional query parameters, per the OAuth specification.

NOTE: Cerner’s implementation uses strict path validation, which includes trailing slashes in your redirection URI.

I’m having trouble registering my redirection URI, what advice can you offer?

URIs must conform with RFC 2396 and must be an absolute URI, per that specification. Most issues we encounter are individuals attempting to register URIs with schemes containing a net path (“//”), but are missing an authority component. For example, “app://” is an invalid URI, but “app://callback” is valid.

Can I register multiple redirect URIs?

Cerner’s operations team can register multiple redirect URIs for your application. This function is not yet exposed in our developer tooling.

My organization is a Cerner client that offers an application directly to patients. Can we skip the authorization interaction with users for our app?

Yes, Cerner offers the ability for organizations providing their own app to disable the patient-mediated authorization workflow when used in context with their organization.

How can I embed my SMART® on FHIR® application in another application, such as inside of a web view or iframe and still orchestrate the authorization workflow?

A general-purpose framework for embedding SMART® on FHIR® applications does not currently exist.

One or more offline access tokens stored by my application may have been compromised. What action should I take to prevent their usage?

Disable or rotate your system account via Cerner Central as soon as possible via Cerner Central System Account Management.

How can I deliver my solution to users utilizing its own Citrix instance with XenApp?

Cerner currently does not have guidance on how to deliver native applications running within their own dedicated Citrix container. Such applications would generally interact with the authorization server from a browser hosted within the application’s Citrix environment, unless other steps are taken to allow for interaction with the browser on the device where Citrix Receiver is run.

Why am I getting an error about having too many scopes?

Access tokens are conveyed to resource servers as HTTP headers, and most web servers place an upper limit on the largest allowable HTTP header. The exact value varies between vendors, but is typically in the 4K-8K range. Since scopes are included in access tokens, using more of them makes the access token larger. If the authorization server detects that it is about to return an access token that would be unusably large, it will return an error instead. Try reducing the number of scopes in your request to the minimum necessary for your application.

References