Skip to content

Instantly share code, notes, and snippets.

@jmandel
Last active August 29, 2015 14:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jmandel/d1eb507a0999d5c0ff22 to your computer and use it in GitHub Desktop.
Save jmandel/d1eb507a0999d5c0ff22 to your computer and use it in GitHub Desktop.
UMA entry-point for FHIR apps

The Goal

Enable a common set of scopes that can be used across UMA-based authorization and "vanilla OAuth 2.0" authorization in a consistent way. In particular, support a model where apps know which permissions they'll need and can get authorized, up-front, with all of those permissions explicitly (rather than attempting a FHIR operation, engaging in an UMA flow... and then repeating this process each time the app needs to issue a new query against the patient's clinical record). Effectively it's a way to standardize the logic by which an UMA resource server knows which scopes to register when it creates an authorization request with the authorization server. Plus a bootstrapping protocol to help determine protected resource URLs (which don't quite occur naturally in a FHIR-based API implementation).

Authorization Process

Preconditions

For each user, the resource server registers user-level resource sets and (user, patient)-level with the UMA authorization server as follows:

  1. A single resourse set indicating "this user's access to any medical records she's allowed to see" -- user-level resource set

  2. For each specific patient this user is allowed to see, a resource set indicating "this user's access to patient p's record" (user, patient)-level resource set

Protocol Flow

When an app wants to get access to an UMA-protected FHIR API endpoint, it will first need to determine a "UMA context url" that's scoped to a user, or to a (user, patient) tuple. This context URL is essentially a throwaway identifier indicating something like:

  • "John Smith's access to any medical records on this resource server" -- for a user-scoped context URL

  • "John Smith's access to his daughter Abigail Smith's record" -- for a (user, patient)-scoped context URL

Note that a resource server knows how to map its UMA context URLs to individual resource sets that have been pre-registered with an UMA server. But the mapping may be many-to-one, and a client application never learns this mapping. The process by which the app discovers an UMA context URL is not important -- but see "Resolution Service" below for one approach.

The app should, ahead of time, decide which FHIR scopes it needs in order to do its job. For example, a Flu Clinic app might need to read allergies and write immunizations, so it would need the scopes AllergyIntolerance.read and Immunization.write.

To ask for these specific permissions the app initiates the following HTTP request:

POST /uma-context/29048298472385192382324848/authorize?scope=AllergyIntolerance.read%20Immunization.write
Host: hospital.org
...

The hospital.org server must understand this UMA context URL, and it must already know which user or (user, patient) it is scoped to. The server then maps this context to an internal UMA resource_set_id that has already been registered with the user's authorization server. In addition, it uses the explicit scope parameter requsted by the app to determine which scopes register in a new request to the authorization server (which results in a permission ticket).

The standard UMA flow continues from here.

Resolution Service

For apps that happen to be operated by a resource owner directly, we can offer a streamlined, standardized approach to resource "discovery", in the form of a redirect-based protocol. Something roughly like:

Precondition

App learns which resource server to talk to -- e.g. by asking the user which hospitals or clinics they want to connect to. For example: https://hospital.org.

Protocol flow

This is an automated protocol for communicating an UMA context url to an app. It's never strictly needed -- the app could, for example, instead ask the user to paste in an UMA context url directly. Importantly, the resource url conveys no actual access privileges or identifying information

  1. App redirects user-agent to https://hospital.org/resolve-uma-context/user or https://hospital.org/resolve-uma-context/patient with query params redirect_uri and state.

  2. Resource server authenticates end-user. In the case of the /user endpoint, an opaque per-user UMA context URL is established. In the case of the /patient endpoint, an opaque per-(user, patient) UMA context URL is established. To help prevent apps from linking users by comparing UMA context URL, a good practice would be for the resource server to generate a new UMA context URL each time this flow occurs.

  3. Resource server redirect user-agent back to https://app?resolved=https://hospital.org/uma-context/29048298472385192382324848&state=123. At this point, the app has an opaque UMA context URL that's scoped to a user or (user, patient).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment