SMART on FHIR – adding OAuth2

You may recall that a week back we had a look at one of the connectathon scenarios – the SMART scenario.

In this post we’re going to take the work that we had done in the last post, and make it secure using the SMART version of the OAuth2 standard. As always, a primary reason I’m writing it down is so that when I forget what I did to make it work – I’ll have this as a reference to remind me <s>. And a reminder – I’m using the Java based HAPI FHIR client, in a web based application running in a Tomcat servlet engine, with IntelliJ IDEA as my IDE.
Read more of this post

FHIR and OAuth2

I’ve mentioned before that one of the reasons I started this blog was to document for myself things I find out about FHIR so that when I forget them, I know where to go and look to find them…

Thus far I’ve focussed on the FHIR standard itself, but one thing that has become increasingly significant are some of the aspects of security – notably Identity, Authentication, Authorization and Audit. Here at Orion Health, we’re building a FHIR interface to support the uploading of glucose results from a patient device and so these are issues we need to address right now. A perfect opportunity for a post!

First let’s agree on some definitions.

  • Identity (in the IT sense) are specific attributes of an entity that identify that entity – such as name, gender, date of birth etc. Note that a single person may have multiple identities – for example I might keep separate identities for LinkedIn and my Bank even though there’s only one of me.
  • Authentication is when we ‘prove’ to some system that the Identity accessing it is who they claim to be. Generally the system will have some piece (or pieces) of information that can be used to make this assertion. For example a username and password is a common way of doing this (though increasingly insecure).
  • Authorization is about specifying and controlling access to certain types of resource. For example, that to access clinical data a user needs to be in the role of a clinician.
  • Audit is where you keep a track of what has been done in the system, about and by whom. In FHIR this is represented by the SecurityEvent resource, which is modelled on the IHE ATNA profile.

And these are all inter-dependant. For example in order to perform authorization you need to have first authenticated the identity of the person wanting to access the particular data and create an audit record when they actually do something which will link to the identity and possibly the authenticator. (I’m well aware that these are very incomplete definitions – but enough for us to move forwards).

Now, FHIR quite explicitly is not a security protocol, and for very good reason as this is really hard to do properly – and there are other groups who do this stuff and produce the required standards. It does provide ‘hooks’ where security-related considerations can be applied (e.g. tags for privacy) and some resources that are useful (such as SecurityEvent and Provenance), and when used over HTTP/S can take advantage of standards like TLS (Transport Layer Security), OAuth2 and OpenID Connect – and it is these latter two that we’re going to focus on in this series of posts.

OAuth2 is a framework that allows an application to access a users data on another server, without that application needing to have a copy of the users credentials on that system.

For example, suppose you write a simple web based application to allow a patient to access their data from a FHIR server. Here’s how your architecture might look:

oauth-1

The user is interacting with pages in their browser which have been served up by the application over the Internet. The application is server side code that is retrieving (and possibly updating) information from the FHIR server – let’s say that’s the users weight observations over time.

Now, the user will have logged into the application (maybe using a username and password), but how does the FHIR server know that it’s OK to deliver up the results for that patient?

One way would be for the user to have an account on the FHIR server, and for the Application to store those credentials and pass them across to the FHIR server when it makes the request. There are a number of problems with this approach.

  • The application now has a copy of the users credentials in it’s store thus increasing the possibility of loss to an attacker. (Weakest links in a chain and all that stuff)
  • What happens when another FHIR server needs to be accessed? Either the user has the same account details on all servers (unlikely), or the application now needs to store multiple sets of credentials for the user.
  • What happens if the user no longer wants the application to be able to access their data? The application has their account details – the user will need to change those account details on all of the FHIR servers holding data about them.
  • Every application and every server will need to store copies of every users credentials – this is going to become a real mess as applications are enabled and disabled, credential details change, and as new FHIR servers are brought into the mix. And the risk of exposure rises significantly…

OAuth2 approaches this problem by separating the role of Authentication & Authorizing, from the role of supplying information (or other services).

oauth-2 (1)

As you can see in the diagram above, there is now a separate component – the Authorization Server. It’s this component alone that holds the users credentials – the other components (the application and the FHIR server) trust the Authorization Server to identify the user and indicate if (and what) data about them can be released to the calling application. (Oh, and note that the components have specific names on OAuth2).

Commonly, the Authorization Server will be some trusted system where the user already has an account – such as Google or Amazon, but can be a separate component – or even functionality of the FHIR server.

At a high level it works something like this.

OAuth2sequencediagram

  1. The user (via their browser) makes a request to the Application (client) and the application needs to get some information from the FHIR server (Resource Server). The Application sends a ‘browser redirect’ back to the users browser, which causes the users browser to make a login request to the Authorization Server.
  2. The Authorization Server delivers a login page to the user.
  3. The user completes the login information, and agrees that the application can access their data (and can also give permission at quite a granular level for the type of information they are prepared to allow access to).
  4. They submit the page back to the Authorization Server.
  5. The Authorization Server validates the login details
  6. The Authorization Server sends another browser redirect back to the users browser, which causes it to navigate to a special endpoint on the application. The redirect contains an ‘authentication code’ that gives the users permissions to access their data.
  7. The users browser is re-directed to a callback end-point hosted by the application. The application:
    1. Calls the Authorization Server with the authentication code it was supplied (plus some other data), and the Authorization Server returns an Access Token (and a Refresh token – we’ll talk about that in a minute).
    2. The Application makes the FHIR query to the Resource Server (the FHIR Server), including the access token in the request (usually the Authorization header).
    3. The Resource Server confirms that the Access token is legitimate, fulfils the request and returns the FHIR data to the application.
    4. The application constructs the page and returns it to the users browser.

 

Some notes:

  • This is a high level summary of the process only, and there are many details omitted. Refer to the spec for details but – as we’ll talk about in a moment – you’ll almost always use a library to implement OAuth2.
  • The Resource Server that requires OAuth2 authorization is commonly referred to as ‘OAuth2 protected’.
  • The mechanism by which the Resource Server (the FHIR server) validates the Access Token is up to the implementer, and there are a number of options:
    • If the Authorization Server component is actually part of the FHIR server, then it could do it directly.
    • The FHIR server could make a separate call to the Authorization Server to confirm it
    • The Authorization Server could sign the Access Token, proving to the FHIR server that it is legitimate.
  • When the Authorization Server returns the Access Token, it also returns a separate token – the Refresh Token, which the application saves locally. The Access Token generally has limited life span – often an hour, and when it expires, the application can use the Refresh Token (which has a much longer lifetime) to get another Access Token. The reason for this complexity is that it allows the Authorization Server to revoke the Refresh Token, which will stop the application from being able to get more Access Tokens and prevent it from accessing the FHIR server after it’s current Access Token expires. Without this mechanism, the FHIR server would have to check with the Authorization Server every time to see if the Access Token had been revoked.
  • This description is a flow that is called the ‘Code’ request type, and is only applicable when the application is capable of keeping the Refresh Token secret. In this scenario it is able to do so as it is hosted on a server (this is a web application remember). If the application (client) is, say, a desktop application or a mobile application, then it cannot do this (someone could hack the device/computer and get it). In this case there is another flow – the ‘implicit’ flow that is used. We’ll talk about that in the next post.
  • The application needs to be registered with the Authorization Server separately to this flow. During this process (which is one-off) the application receives a code by which it can identify itself to the Authorization Server, and also supplies the applications callback address where the browser will be redirected after the user logs in.
  • The security of OAuth2 absolutely depends on using secure transport mechanisms – which is why Transport Level Security (TLS) such as SSL is absolutely required.
  • In addition, the details of the flow is quite complex (the description above is just a summary – there are lots of other details) and there is a strong recommendation to use one of the open source libraries that are available. There’s a list on the spec page.

Well that’s about enough for now – but there’s much more to talk about. Next time we’ll cover:

  • The Implicit flow which is used by Desktops and Mobiles
  • The OpenID Connect standard – which sits on top of Oauth2 and provides some identity functionality
  • Some thoughts on Architecture – specifically in the New Zealand realm!

And finally – I’m not a security expert – if I’ve made mistakes or if something is unclear then do let me know and I’ll make whatever corrections are required.

Some references:

The OAuth2 Specification

A post on Grahames Blog. This points out some issues with delegating authorization..

A tutorial by Jakob Jenkov

Blue Button

SMART on FHIR