The User-Managed Access (UMA) protocol is a specification with deep roots. Based on OAuth in both concept and technology, UMA seeks to address the problem set of access delegation. Instead of a user delegating access to a piece of software they’re using, like in OAuth, UMA allows a user to delegate access to a piece of software that someone else is using. Version 2.0 of the protocol was recently released by the working group, pending final ratification from its host standards body.
Where UMA Began
UMA started before OAuth 1.0 was originally ratified, and UMA has gone through many shifts over the years. UMA set out to solve a variety of use cases, from allowing personal authorization servers, to delegating to another user, to asynchronous authorization. It was an ambitious goal and a lot of good work went into its development. By the time UMA 1.0 was ratified in 2015, the protocol was based on OAuth 2.0 and its extended ecosystem, including dynamic client registration and token introspection.
When the 1.0 specification was finalized, a number of different groups, including an engineering team that I ran, tried to apply it to their problem spaces. We were working in the healthcare space and trying to use UMA for a patient delegating access to her medical records to different physicians. What we found was that UMA 1.0 worked, but it worked in a smaller scope than it originally intended. We ran into walls caused by assumptions made in the design of the UMA 1.0 protocol, assumptions that didn’t hold true for what we needed. For example, it was impossible in our system for an external user to get an OAuth access token, but in UMA 1.0 an access token is required before the transaction starts. This effectively limited our use case to having doctors from a single practice, which wasn’t acceptable in the larger run.
My team took a step back and asked, “What would UMA look like for our use case if we built it ourselves today?” We built a proof of concept of the ideas that came out of these conversations to help test how viable our alternative approach was when implemented on real code. We found that by changing a few key functions and aligning with other specifications, we could achieve UMA’s functionality without the blocks we had seen before. We wrote up our changes and submitted them to the UMA working group, along with rationalizations and pointers to implementations of alternatives. Combined with input from a variety of other engineers and projects, UMA 2.0 was ultimately born.
So, what’s new?
An OAuth Extension Grant
In UMA 1.0, the client needed to go to a special endpoint to get the requesting party token (RPT). This endpoint took JSON in, required a special access token to call it (see the section on AAT/PCT for more on that), and output a JSON structure that included the RPT. This RPT was a special kind of access token that was used like an OAuth access token but had resource-specific permissions attached to it instead of scopes. Of course, the client application didn’t know about that difference and treated the token as an opaque string, just like in OAuth.
In UMA 2.0, we realized that this process wasn’t just similar to OAuth 2.0, it was a copy of OAuth 2.0’s token endpoint with an incompatible syntax. To address this, we used one of OAuth 2.0’s existing extension points. We got rid of the special endpoint and instead re-used the OAuth 2.0 token endpoint with a new grant type. This allowed us to re-use the existing structures that other OAuth 2.0 grant types use, including syntax and client authentication methods. We also immediately got access to any extensions to OAuth 2.0, such as refresh tokens and other additional token types, advanced client authentication methods like asymmetric keys, and anything else that OAuth 2.0 grants could use. Implementers could now build UMA support into an existing OAuth 2.0 server by adding an extension grant type instead of implementing an entirely new endpoint. Finally, the token issued was now, as far as the client was concerned, a plain old OAuth 2.0 access token.
AAT to PCT
UMA 1.0 required the requesting party to perform an OAuth 2.0 transaction with their client to get the authorization access token, or AAT. The AAT was intended to represent the binding between the requesting party and the client, and it was used by the client to call the special token endpoint that we talked about above when discussing the OAuth extension grant for UMA 2.0.
This setup works fine if your requesting party can log into the authorization server and issue OAuth tokens, but the promise of UMA was that the resource owner could share with arbitrary parties using a widely flexible claims gathering system. After all, if the requesting party could just get an OAuth token in the first place, did we really need all the extra parts of the protocol?
We realized that we could accomplish the goals of the protocol without using the AAT at all. It was thought that the AAT could be used in a variety of other interactions with the authorization server, but it turned out that this was the only action ever built out. And since getting the AAT needed the client to authenticate anyway, we could just have the client directly authenticate to the token endpoint when getting the access token.
The thing is, the AAT did have one nice aspect: since it represented the combination of the requesting party and client across multiple resources, the requesting party wouldn’t need to keep providing the same claims over to access new resources. Instead of relying on a side effect, we created a new kind of token in UMA 2.0: the persisted claims token, or PCT. The PCT is issued alongside the access token and it represents all of the claims that the requesting party presented during the transaction. When the client comes back to ask for access again, it can send the PCT in its initial token request. If the authorization server chooses, the claims represented by the PCT can fulfill the policies set by the resource owner.
Since UMA 1.0 began its life many years ago, long before OAuth 2 was ratified, it had to invent many things for its own use. These inventions were codified into the protocol upon its publication, but the standards world has moved forward and general solutions are now available for many of the components that UMA 1.0 had made. In addition to the OAuth 2 extension grant, UMA 2.0 makes a concerted effort to use and extend these solutions.
For discovery, UMA 2.0 uses the OAuth authorization server metadata draft specification. This spec defines a simple JSON document with a set of attributes about the AS. UMA 2.0 extends this with a handful of UMA-specific elements, such as the endpoint where the requesting party can interactively supply claims to the AS.
UMA 2.0 extends dynamic client registration and introspection with UMA-specific components. While both of these technologies can trace their origins in part back to UMA 1.0’s development, they now exist as standalone artifacts in the greater OAuth ecosystem. While UMA 1.0 referenced these, the extensions are even cleaner and simpler in UMA 2.0.
These choices allow developers to make use of general-purpose libraries that support existing standards instead of having to write completely custom code.
The syntax of the protocol was simplified from previous versions. UMA 1.0 had many places where things were left open for extension. Formats such as objects and lists were used in several places where it was thought there might be complex or multiple values. Deployment experience with UMA 1.0 showed us that, in fact, simple values such as strings and numbers could be used instead because nobody was taking advantage of the additional flexibility. Therefore, the complex structures were flattened to reflect the reality of the protocol’s use.
Finally, the specifications themselves were reorganized. Previously, UMA 1.0 was available in two specifications: UMA Core and the OAuth Resource Set Registration spec. The former was more or less everything in UMA, and the latter was meant to be an independent module that could be used orthogonally to UMA. It turned out that resource registration made many assumptions about the environment that it was in, and consequently it couldn’t be used separately without jumping through some seriously convoluted hoops.
Once we had rebuilt UMA 2.0 as an OAuth 2 grant type, we realized that we could restructure the documents as well. The new UMA 2.0 document has the grant as its core, with all of the elements required for its functionality in the same document. This set includes claims gathering, permission tickets, token issuance, and other central components. However, while UMA 1.0 assumed that the connection between the authorization server and resource server was always loosely coupled, UMA 2.0 makes no such assumption and moves the components required for that loose coupling to a secondary document for federated authorization. In UMA 2.0, it’s entirely possible to set up a system to use the UMA grant that is tightly coupled together, not requiring token introspection or resource registration to happen over an interoperable protocol.
Go Use It
As of this writing, UMA 2.0 is in final review in its home standards body. The protocol has been simplified, it addresses more use cases, and it has better security properties. I, for one, think this is a strong indication that the spec is moving in the right direction. Now’s the time to go build it and use it, to see where it works and where it falls short. I’m sure we’ll find lots of interesting ways it can be applied, and we’ll probably dig up some interesting ways that it fails very reasonable expectations. Whatever happens, we’re sure to learn something and push the state of security forward.