Torsten Lodderstedt’s excellent blog titled “Transaction Authorization or why we need to re-think OAuth scopes” has been floating around for a few weeks. I always meant to have written this earlier, but did not have a chance, so here is my first attempt.
I. On the Claims parameter in OpenID Connect
OpenID Connect’s claims parameter actually came in quite late. We had Request Object (aka JWT Authorization Request) before it and the Claims parameter came in to make the picture complete so that encapsulating the authorization request simply into JWT will result in the Request Object.
The rationale for having claims parameter in the Request Object was that we as the WG determined that the introduction of structured syntax to scope was going against the philosophy of “space delimited strings” in RFC6749. So, instead, we decided to do what seemed minimally invasive to the implementations by introducing a scope called “openid” as a switch so that the implementations can switch the behaviour.
After the implementations detect “openid” in the scope, it was intended that the further scopes were to be interpreted in the “openid” way. In particular, it should look for
Claims parameter is a generic mechanism to pass potentially dynamic values to the Authorization Server. While OpenID Connect defined a few additional scope values such as
profile, they are intended to be just an alias to defined claims structure, at least in spirit.
For more information about it, please refer to “Scopes And Claims In OpenID Connect” (2012-01-26).
II. Request Object / JWT Secured Authorization Request
A bit of history to start with: OpenID Connect started with a use case called Transaction Exchange (TX), which later was changed to Contract Exchange (CX). The CX working group is still there for us to go come back and complete the work.
Because Transaction or Contract Exchange was the original use case, it was quite clear that we had to have a signed authorization request and signed response. The Request Object took care of the former.
It is quite easy to imagine that the Request Object gets quite bulky as it may include various parameters that are to be included in the contract. So, sending it in the Authorization Request as part of the URI parameter in the HTTP redirection was quite unrealistic. Thus, we needed a facility to pass the Request Object to the Authorization Server by reference, aka “artifact” and such protocol binding was called “Artifact Binding” in SAML. Thus, a Working Group at OpenID Foundation called “Artifact Binding WG” was formed. This is the OpenID Connect WG now.
While you may have gotten an impression that the Request Object is to be stored in the Client from Torsten’s article, in fact, OpenID Connect deliberately does not specify where the Request Object should be stored. Section 6.1 of OIDC just says:
The Client stores the Request Object resource either locally or remotely at a URL the Server can access. (Source) https://openid.net/specs/openid-connect-core-1_0.html#CreateRequestUri
The part “The Client stores” above is just describing the fact that the client makes an action to store the request object and does not mean that it needs to be stored in the client. In fact, in the case of a pure mobile app, it cannot obviously stored in the client as the authorization server then cannot access it to retrieve the content referred by the reference.
There are three potential locations that could serve as the Request Object.
- Authorization Server
- A third party provider
- The client
However, OIDC does not specify how to store the request object in those locations. This is what needs to be further specified as an option. The reason we did not specify it in the OIDC Core is that there can even be a “manual way” of storing those request through a web page provided by the authorization server or a third party provider, where the content of the request object may be static. (Note we had
state value excluded from the Request Object for the purpose. This is the delta between the OAuth JAR and OIDC.)
You might think the manual creation of a request object is absurd. It actually is not when you think about the legally binding contracts. For a digital signature, you are typically required in many jurisdiction that to sign it in person using your own certificate, such as that of eIDAS.
III. Pushed Request Object
Pushed request object described in FAPI Part 2 is an attempt to define the pattern 1 above. Sending the authorization request (request object) to the authorization server is the most logical pattern where the client can directly communicate with the Authorization Server. (Note that this is not always possible, e.g. the case of the AS being behind the firewall or running as the mobile app. )
As to the method of client authentication, we had two options: being explicit or doing it implicitly with the client signature over the Request Object. We have chosen the later as it will reduce the implementation burden.
In Torsten’s article, this approach is evaluated of having the following disadvantage:
But the pushed request object as described so far still does not overcome one of the key disadvantages of the “scope-specific URI query parameter” pattern: It requires the authorization server to be aware of application specific relationships between scope values and URI query parameters (e.g. “payment” & “payment”) making a fully generic implementation of this pattern in OAuth products difficult to achieve.(Source) https://medium.com/oauth-2/transaction-authorization-or-why-we-need-to-re-think-oauth-scopes-2326e2038948
From the OpenID Connect point of view, I have some reservation against the statement.
First, since the payload will include an application specific content, the Authorization Server needs to be aware of the context and associated parameters. So, understanding the context should not be a problem.
Second, you do not have to map the scope and the parameters endlessly. In fact, in case of OpenID Connect, there is only one parameter:
claims. The intent was that any extension goes into the protocol underneath it. The logic at the AS then is:
- First, look for
openid in the scope value.
- If it finds it, transition to OpenID Connect mode and look for claims parameter. (There are several shortcut scope value in lieu of the associated claims parameter but they are just there for convenience.)
Similar conventions can be used for other applications. Or, why not just write as the sub-application of OpenID Connect? Then you do not need to extend the authorization parameter at all.
IV. Structured scope
By now, you must have become aware of it. Yes. There is a structured scope in OpenID Connect. The name of the parameter is called “claims”, and the switch to tell that the application is using a structured scope is a scope value “openid”.
Why do we need a new parameter
structured_scope then? 😉
We designed them back in 2011. The world is finally catching us up!