These labs are designed to demonstrate how SMART(R) is used to access protected API resources. For the lab, Cerner provides a demo application such that participants can see each step of the process from within a web browser.
This lab demonstates the OAuth 2 protocol messages used by SMART(R) to request access on behalf of a user and obtain an authorization (access) token.
https://code-console.cerner.com/console/apps
Make sure its a DSTU2 Provider app with all patient and user resources selected
- Redirect URI https://authz-demo.cerner.com/client/demo/cb
- Launch URI https://authz-demo.cerner.com/client/demo
- Copy the Client Id and save it for now
- Click the button "Test Sandbox" and launch Timmy Smart
The web console will output useful information about the specific steps being performed to orchestrate the authorization process. Perform the following steps to open it in your browser:
- Chrome: Ellipsis Menu->More Tools->Developer Tools->Console
- Firefox: Tools->Web Developer->Web Console
- Edge / IE: F12 key->Console
In the box labeled "2", fill out the following parameters. These parameters are used to construct the authorization request to the authorization server.
-
Auth Server URI: https://authorization.cerner.com/tenants/ec2458f2-1e24-41c8-b71b-0e701af7583d/protocols/oauth2/profiles/smart-v1/personas/provider/authorize
- This is the "authorization" endpoint where the authorization request will be submitted to.
- It is the entry point that will guide the user through steps to confirm their identity, and conditionally, provide consent.
-
Client ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
- This is the unique identifier that this application uses to identify itself with the above authorization server and should have been saved in Step 3.
-
Scope(s): user/Patient.read
- This is the access being requested by the demo application.
-
Launch Code: (varies)
- For now, copy, save for later, and delete from this field
-
Aud: https://fhir-ehr-code.cerner.com/dstu2/ec2458f2-1e24-41c8-b71b-0e701af7583d
- This is the base URL hosting the services that will be accessed.
- The authorization server verifies this is a URL known to it, as to prevent you from accidentally sending tokens to a malicious party.
Note: An additional parameter "state" is automatically generated for you by the demo application. Your client application should generate and store its own state value associated to a given device to prevent malicious parties from orchestrating a "session fixation"-style attack.
- Click "Get Authorization Code"
- A second window will open to orchestrate authentication / authorization.
- Enter the lab credentials, click log-in.
- This tab should close, and the previous tab should foreground.
In the box labeled "3", make sure the following parameters have been pre-populated:
-
- This is the URL where the token request will be submitted.
-
Client ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
- This is the unique identifier that this application uses to identify itself with the above authorization server and should have been saved in Step 3.
-
Code: (varies)
- This the authorization code sent by the authorization server at the completion of step 4.
- Click "Get Access Token"
- If an error occurs, the authorization code may have expired.
- In this event, perform step 3, 4, immediately followed by this step.
- The text area in the box labeled "3" contains the token response
from the server.
- The "access_token" is a bearer token that is used to access web services.
- The "scope" indicates what the server or person granted your client application (more on scopes later).
- "expires_in" declares the number of seconds for which the access token will remain valid.
- Examine the web console for details on how the field values were constructed into requests used to orchestrate authorization.
This lab demonstrates the usage of an access token to access a protected service.
- Repeat steps 5-8 of Lab 1.
- Click "Get Access Token".
- In the demo application, locate the field named "Resource Server" section 4 "Access protected resource"
- Click "Access Protected Resource"
- In the text field labeled "Access Token", modify the value of the JSON value of "access_token".
- Click "Access Protected Resource"
- What response was returned from the service?
- Repeat steps 5-8 of Lab 1.
- Click "Get Access Token"
- In the demo application, locate the field named "Resource Server" in section 4 "Access protected resource"
- Submit the Request
- Note the "403" error response code (the scopes requested did not include the Practitioner resource.)
- Repeat the authorization request with the additional scope of "user/Practitioner.read"
- Repeat the token request.
- Confirm that "user/Practitioner.read" is returned in the list of scopes.
- Repeat the resource request.
- Confirm a resource is successfully returned.
- Repeat the authorization request with the additional scopes of "user/Fictitious.read system/Patient.read"
- Repeat the token request.
- Confirm that neither of these scopes are returned in the list of scopes.
This lab demonstrates how OAuth 2 endpoints are discovered via a FHIR(R) Conformance document.
- In section "2" of the demo application, delete the value of "Auth Server URI" and "Aud".
- In the section "3" of the demo application, delete the value of "Token URI".
- In section "1" of the demo application, enter the following value for "FHIR Base URL"
- Click "Discover Authorization URLs"
- Verify content for the conformance document was returned.
- Verify that "Auth Server URI" in section "2" of the demo application now matches the value from Lab 1.
- Verify that value "Aud" in section "2" of the demo application now matches the value from Lab 1.
- Verify that "Token URI" in section "3" of the demo application now matches the value from Lab 1.
Note: This lab requires a launch code (saved in Lab 1 Step 5) for the patient "Timmy SMART".
- The URL will contain a launch code (shown below in notes), append it to the launch URL of the demo application.
- Note the FHIR Base URL is populated with the "iss" value.
- Note in section 2 of the demo application that the "Launch Code" value is populated with the "launch" value.
- Note in section 2 of the demo application that the "aud" (audience) value is populated with the "iss" value.
Note: The callback URL for the demo app will be similar to the following:
- In section "1" of the demo application, click "Discover Authorization URLs".
- In section "2" of the demo application, enter the scopes "patient/Patient.read launch"
- Click "Get Authorization Code".
- If prompted, enter credentials.
- Click "Get Access Token"
- Note the additional fields returned in the token response, including the identifier for the patient record (Patient/1316024)
- In the demo application, locate the field named "Resource Server" section 4 "Access protected resource".
- Click "Access Protected Resource"
- In the demo application, locate the field named "Resource Server" section 4 "Access protected resource".
- Click "Access Protected Resource"
- Note Access is Denied (Status = 403).
- Switch the scopes to "user/Patient.read launch", then click "Get Authorization Code".
- Click "Get Access Token"
- Click "Access Protected Resource"
- Note that you are able to access the resource using the "user"-qualified scope, whereas previously the "patient"-qualified scope constrained the client's permissions to the launched patient record.
This lab will demonstrate how OpenID Connect identity tokens can be obtained as part of the authorization exchange.
- In section "1" of the demo application, click "Discover Authorization URLs".
- In section "2" of the demo application, enter the scopes "user/Patient.read openid"
- In section "2" of the demo application, remove the launch code
- Click "Get Authorization Code".
- If prompted, enter credentials.
- Click "Get Access Token"
- Note the presence of "id_token" in the token response.
- Open the website http://jwt.io/ in a new tab.
- Paste the contents of the id_token into the website.
- Examine the decoded contents
Note: The subject + issuer combined are considered the globally unique "identifier" for a given user. Note: NEVER enter tokens from a production environment into jwt.io unless such tokens are expired.
- Examine the decoded token header in jwt.io
- Note that the "alg" parameter is RS256.
- This token is signed using an RSA key over a SHA-2 hash.
- Tokens from other implementations may be signed with an "alg" of "none".
- Note the value of "kid" (key ID) for step 7.
- Note that the "iss" (issuer) is different than the token endpoint.
- Append "/.well-known/openid-configuration" to the issuer value:
- Paste this URL into a new tab in your browser.
- Note the URL in the field "jwks_uri" in the OpenID configuration document.
- Paste this URL into a new tab in your browser.
- Locate the RSA key with a key ID ("kid") matching that from step 5.
- This is the key that would be utilized to verify the signed JSON Web Token.
Note: Many JWT libraries provide utilities to perform token signature verification and for parsing JSON Web Key Set documents.
This lab demonstrates the use of refresh tokens. Refresh tokens are used when an application needs to access services on behalf of a user for an extended duration, or when an application needs to delegate a subset of its authorized scopes to a subsystem within the applications own architecture.
- In section "1" of the demo application, click "Discover Authorization URLs".
- In section "2" of the demo application, enter the scopes "user/Patient.read online_access"
- Click "Get Authorization Code".
- If prompted, enter credentials.
- Click "Get Access Token"
- Note the presence of "refresh_token" in the token response.
- Note a "Refresh Access Token" button appears.
- Note the content of the current token response.
- Click "Refresh Access Token"
- Note that a new access token is returned with a new token response.
- In a separate tab, open the following URL:
Note: This is a private log-out mechanism, used by the authorization server to end a session, and not a contract offered by SMART.
- Click "Refresh Access Token"
- Note that the refresh fails.
Note: Existing access tokens are still valid until they expire.
This lab demonstrates a number of commonly-encountered error cases, and how the error response can be used to link a user to an appropriate error page with more information.
- In section 2, remove the "aud" parameter.
- Click "Get Authorization Code".
- Note the x-www-form-urlencoded query parameters returned in response contain an error and error_uri.
- Extract the error_uri parameter
- URI-decode the error_uri value (https://www.bing.com/search?q=url+decoder)
- Visit the URL in a separate tab.
- Note the user-facing elements of Cerner's error pages:
- An error message with support contact information.
- An error message for developers.
- A "correlation ID" for assisting troubleshooting / diagnosis.
- In section "2" of the demo application, replace the value of "aud" with the following:
- Click "Get Authorization Code"
- Click "Get Access Token".
- Click "Get Access Token" a second time.
- Note the error that returns.