Securing your REST API
Apr 25, 2013Over the weekend, I spent several days working on integrating OAuth authentication and authorization into my FHIR server. Really, I’m primarily interested in authentication - if the user authenticates to the server, they get open access. So the functionality I implemented was that I will accept logins from any Facebook or Google user. Integrating with Google and Facebook was almost ridiculously easy - The only thing that slowed me down was the documentation for the Google call to get a user’s profile details - I needed to provide an Application Key for charging purposes (not applicable at my volume though), and the documentation for the login process didn’t mention that (I found the solution on stack overflow).
But doing this generated some interesting discussion between the FHIR implementers preparing for the upcoming connectathon about the usefulness or otherwise of OAuth as a authentication protocol for a FHIR RESTful API. To illustrate the problem, consider this architecture, which seems like a pretty common architecture for the kind of FHIR deployments involving OAuth:
In this case, the user logs into the healthcare application - which is likely to be either a mobile or a web application, and authenticates to it using OAuth via something like Facebook, Google, etc as the OAuth server. For the user, this is convenient and observationally we know that this is really important. But, then, on their behalf, the application wants to use one or more FHIR services. How does this work? It’s pretty hard to find good information about this on the web, and the standard advice - such as this one here - really just doesn’t address this question well (at least, not that I could find).
As far as I can see, you have several options to handle this case:
- The FHIR services - which offer the FHIR RESTful API - don’t authenticate the user. They authenticate the healthcare application, and the user is invisible to FHIR service, and vice versa
- The FHIR services use OAuth themselves. The healthcare application asks the user to log in to each FHIR service provider independently using OAuth.
- The FHIR Services provide a custom login which allows the healthcare application to pass the OAuth access_token to the FHIR services - they can use this to authenticate the end-user
I find each of these unsatisfactory for different reasons.
The first option can work just fine, but the user (patient, for example) has no visibility of the data storage, and there’s no really any capacity for the user to share their own data in their own way. Whether that’s good or not depends on the context. If it’s good, then the first option is for you. And so in this case, OAuth is not appropriate on the RESTful server - just some kind of application secret
The second option has the advantage that the user is explicitly aware of the data storage, and manages that directly. They can have multiple data stores, and explicitly grant access to a particular application. That’s a different kind of use case that would work well for a few users, but would simply bamboozle the majority of users, especially those who most need healthcare and to share their data. I think that this would be a problem for the healthcare application offering. But this is the consequence of the RESTful API offering OAuth based authentication. (btw, There’s a supplementary technical problem for a web based healthcare application in this case - at the end of the authentication process, the user will get redirected away from the healthcare application to the RESTful API provider. There’s a variety of options to deal with this, but they all have problems).
The third option works well in practice, but does mean that the FHIR service provider gets the same level of access to the user as the healthcare application - and the healthcare application has to trust the FHIR service provider to impersonate it.
Tim Bray pointed out (thanks!) that there’s a 4th option if you login through Google - as part of the OAuth process, Google returns an OpenID connect JWT token, and rather than sharing the access token, the healthcare application could just pass the id_token to the FHIR Service. The FHIR service could use the id_token to verify the user identity, and that access has been granted to the application by the user. This would mean that the FHIR service has no access to any Google services associated with the user (including getting basic descriptions of the user) - it would need the access token for that. Another problem with this approach is that Facebook doesn’t generate a token like this (or any functional equivalent, so far as I could see anywhere).
Choosing to secure your RESTful api using OAuth isn’t as straightforward as it seems, then.
p.s. My server supports all 3 options from the top list - see the documentation.
Update: Related Links
- More Thoughts on OAuth Access Sharing
- Sharing Access Tokens Across Apps (note the OAuth rule, which is the kind of safe thing committees do, that isn’t really practical in the real world)