The purpose of scopes is sometimes misunderstood. The OAuth2 specification uses scopes as a mechanism for an application to request specific API permissions for actions it wants to perform.
A scope enables an app to request the permission it needs to do something on the user’s behalf. So an app that only provides data viewing capabilities of some sort (e.g., viewing a patient’s appointment schedule or accessing lab results) should only be allowed to request read scopes.
When setting up a new SMART on FHIR application that will consume FHIR APIs, one of the most important security considerations is which scopes to allow the app to request.
Important! It’s important to remember that scopes are not user permissions, they are application permissions. For example, a clinician user might have read/write permissions against the CDR, but if an app they are using has only been granted read permissions, the app cannot write data on the user’s behalf.
One decision that needs to be made is whether to prompt the user for scope approval. Opala fully supports allowing the user to see which scopes an app is requesting, and make a decision about whether to approve them. Internet users are familiar with this workflow, as it is often seen when granting consumer internet apps permissions to see a user’s profile information via common "Login with Google" and "Login with Facebook" type flows. This scope approval flow happens on the OpenID Connect Approval Page (sometimes called the "Consent Screen").
The explicit user approval step is not mandatory. Scopes may be configured as Auto-Approve on the Client Definition screen if an organization wishes to approve these scopes automatically without showing them to the user. This might be done for enterprise apps where the app is fully trusted, or in cases where the app has been vetted by an organization and is believed to not require user permissions.
Scopes can even be configured as Auto-Grant, which means that they will be granted any time a successful authentication occurs, even if the application did not request them.
Scopes are short strings of text with no whitespace in them. For example, in SMART on FHIR, the patient/Encounter.read
scope can be used by an application to request to access Encounter resources belonging to the currently authorized patient.
Note: Each SMART on FHIR scope has a user-visible text description that can be customized.
Opala suggests that at a minimum you use the following scopes for your application:
openid profile
fhirUser launch/patient offline_access online_access openid patient/*.read profile
Opala believes, however, that you should use the following more complete listing of scopes where possible:
openid profile
flaunch/patient fhirUser offline_access online_access 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/Medication.read patient/MedicationRequest.read patient/Observation.read patient/Organization.read patient/Patient.read patient/Practitioner.read patient/PractitionerRole.read patient/Procedure.read patient/Provenance.read patient/QuestionnaireResponse.read patient/RelatedPerson.read patient/ServiceRequest.read
Note: openid
and profile
are default scopes already included in the client definition.
In many cases, an app can be authorized without knowing which patient it is expected to display.
For example, consider a third-party mobile app that is authorizing itself against a hospital Patient Portal that acts as both a SMART on FHIR compliant Authorization Server and Resource Server. Users already have an account (with username and password) in the Patient Portal application and by authorizing against those credentials the mobile app can download data from the Patient Portal.
In this case, the user is associated with a Patient Resource ID on the Resource Server, but neither the mobile app nor the user are aware of what resource ID that would be.
Another use-case for launch scopes consists of a portal which functions as the "desktop" of micro-applications (small web applications that do only one thing, and do it well).
In this case, it could be assumed that the portal itself has a concept of which patient (and/or which practitioner, which location, etc.) is currently selected. The user’s expectation would be that if a patient is selected in the portal, any micro-apps would launch with the same patient selected.
SMART on FHIR specifies a set of scopes which request that the Authorization Server return the launch context to the client. These scopes are named launch/[type], where [type] is one of patient
, location
, practitioner
, or another type of your choosing.
From the client’s perspective, a flow using a launch scope works as follows:
launch/patient
scope. This is a request for the Authorization Server to include a patient launch context.
http://myserver:9200/oauth/authorize?response_type=code&scope=openid+profile+launch/patient&client_id=my-client-id&state=af0ifjsldkj&redirect_uri=https://myapp.example.com/cb
access_token
and id_token
are received, the response will contain an additional claim called patient
.
{ "access_token":"eyJraWQiOiJ1bml0dGV (..snipped..)", "token_type":"bearer", "scope":"launch/patient openid profile", "id_token":"eyJraWQiOiJ1bml0dGVzdC1 (..snipped..)", "patient":"123" }
"patient": "123"
claim.The openid
and profile
scopes are used by the client to request user identity information from the Authorization Server as a part of the authorization flow.
When these scopes are requested, an additional claim is returned by the authentication server called id_token
. This claim is the ID Token and you can see it being returned in many of the examples above.
The ID Token is a signed JWT. It may be decoded, revealing a number of attributes.
{ "jti":"d34af0de-e65a-4c19-8e38-365916948356" "at_hash":"xDKTbwLJPrb6hr_loWD8Qw", "sub":"user123", "profile":"http:\/\/example.com\/issuer\/fhir\/RelatedPerson\/123", "iss":"http:\/\/example.com\/issuer", "nonce":"NONCETEXT-123", "aud":"my-client-id", "auth_time":1532416414, "exp":1532416474, "iat":1532416414, "name":"John Smith", "given_name":"John", "family_name":"Smith", }
If you receive a 401 Access Denied error when attempting to retrieve data from a FHIR resource, it is likely because you haven’s included that FHIR resource in the Required Scopes section of the Sandbox Settings page on the Opala Developer Portal or in the Request Scopes field of the App Registration wizard.
If you need to add a scope to the Sandbox, you can add it directly on the Sandbox Settings page. However, if you need to add a scope to your application, you must re-register the app using the App Registration wizard and include the needed scope in the Request Scopes field (see the Third-Party Application Management section in Getting Started in this documentation set).