Subject: [OAUTH-WG] A Note on OAuth Interoperability

From: Justin Richer <[email-masked]>
Date: Wed, 9 Oct 2013 11:00:11 -0400

From many conversations that I've had with people over the past few 
years, it's been clear to me that there's a significant amount of 
confusion about the state of interoperability in OAuth. All notions of 
profiles and deployments aside, I believe that many people have 
different ideas about *what* exactly is meant to be interoperable within 
OAuth, and these expectations lead to premature declarations of OAuth 
being non-interoperable. The truth is that there are a lot of moving 
parts in OAuth and different parts of the protocol family deal with 
interoperability between different pieces. I'm going to attempt, here, 
to lay out what I see as the fundamental interop concerns that each 
component deals with, and hopefully this can help drive the conversation 
forward in a constructive manner:

RFC6749: client <-> AS

The core spec deals with interop between the client and the 
authorization server, in four different flows that tell the client what 
it needs to do to get a token. (Five if you count refresh tokens.) The 
resource owner/user agent are used as mechanisms to facilitate the 
interaction between these parts, but they are by and large passive 
carriers of the information being passed along the front channel. It's 
important to realize that RFC6749 doesn't say anything about 
interoperating with the protected resource. It's also important to 
realize that RFC6749 doesn't say anything about interop between the 
resource owner/user agent and the client, or between the resource 
owner/user agent and the AS. The core is, by design, silent on these 
matters.

RFC6750: client <-> PR

The bearer token spec deals with interop between the client and the 
protected resource by defining one kind of token and telling the client 
how to use it at the PR. In defining the token type, it does define what 
would is returned from the AS. This, however, I think is an unfortunate 
artifact of the core not defining an abstract object structure 
representing the token, and instead defining only the JSON serialization 
coming from the token endpoint's output (which is then serialized in 
parameters in the implicit flow, and maybe we can fix this all in OAuth 
2.1, but I digress). However, the core of this spec is to tell the 
client what to do once it gets a token. Ultimately, RFC6750 doesn't care 
how you get a bearer token, and we've seen many instances of issuance of 
bearer tokens that don't use any RFC6749 constructs. But once you get 
that token, and it is a bearer token, then a client can use RFC6750 to 
hand that to a protected resource. RFC6750 is also silent about what the 
protected resource does to figure out what the token's good for, or if 
it's any good at all.

JWT, Introspection: PR <-> AS

Since everything to this point has been completely hand-wavy about how 
the heck a PR and an AS can agree on what to do with a token, these two 
specs (and their associated ecosystems) solve it in different ways. Of 
course, the most common approach, and the one assumed in OAuth 1.0, was 
that the AS and PR were actually the same thing. But since we can 
theoretically split these two in OAuth 2.0, we need some means to get 
them talking. JWTs pack information into the token itself, building 
directly on top of RFC6750's bearer token (for the most part), and use 
JOSE to provide different flavors of protection and assurance. A common 
pattern with JWT that I've seen is to have something that can facilitate 
service discovery in the "iss" field (like a URL), and then 
asymmetrically sign it with the AS's key so that the PR can check the 
signature. Then everything in the token can be used to figure out 
important things like who the token's for and what it should be used 
for. Introspection uses a web-API approach to solving the same problem, 
where the PR makes an HTTP GET and passes the token along back to the AS 
to get this information. Both have their benefits and drawbacks and can 
even be used together (ie: parse the JWT to find the issuer, then call 
introspection on that issuer).

Then you have things like Revocation which deal with token-holder <-> 
AS, where token-holder can be either the client or the PR depending on 
what's trying to be accomplished. Registration deals with client <-> AS, 
resource provisioning deals with PR <-> AS, and of course there's UMA 
which connects everybody to everybody else by using most of these 
components in a single, comprehensive application of awesomeness.

Where have we gone awry on this? For starters, current revision of the 
signed token spec attempts to solve both client <-> PR and PR <-> AS 
interoperability simultaneously, and I think that's a mistake. There are 
also those who assume client <-> AS and client <-> PR interoperability 
as indivisible from each other, which is also a mistake. And then there 
are those that see that one spec or another doesn't specify interop 
between all points on its own, so they conclude OAuth is fundamentally 
non-interoperable. This is a grave mistake but it's a very real problem 
of perception that OAuth has in the real world.

I think that as we go forward with OAuth interop testing and continued 
profiling, we need to keep in mind *what* is interoperating with *what* 
for each piece that we care about.

  -- Justin