In my last post I alluded to the tension between real-world token-based security architectures, the OAuth 2.0 scope model, JWT access tokens and the audience claim.
We went through a couple of iterations in IdentityServer how we deal with those concepts.
By that time OAuth/OIDC and the usage of JWTs was very new, so everybody made their own sense of these technologies – especially how they are supposed to work together.
We decided that the audience claim in JWTs doesn’t really map to OAuth and its scope concept, so we didn’t really use the aud claim. Instead we emitted the granted scopes in the scope claim.
Mostly to make JWT libraries happy, we also emitted a static aud claim. The format was issuer_name/resources and was a way in APIs to make sure that this is an access token coming from a certain issuer.
In IdentityServer4 we introduced the ApiResource abstraction to make it easier to structure the API surface. In our configuration model, you could add named APIs that could act as a container for scopes and other settings. If an API resource did not define an explicit scope, we added one under the covers with the same name as the API.
We continued to emit the granted scopes in the scope claim, but also started emitting the API names as the aud claim. We also made the static aud claim optional.
This led to many scenarios where the aud and scope claims were identical, and it felt wrong to force everyone into the resource abstraction – and certainly against the original spirit of OAuth.
With the advent of the resource indicator spec, we finally have a more formalized way how resources relate to scopes – and this is also a perfect match for our resource configuration model.
But at the same time, we’ve done a lot of consulting for very different types of OAuth-based installation over the last years to know, that not everyone needs the resource concept.
That’s why we decided to give you more control – you can either model scopes as a flat list, or hierarchical. Which means you can go from a very simple model like read/write/update scopes to very complex namespaced resource/scope combinations. Also sharing scopes between resources is now possible as well.
We made the aud claim optional again (for a scopes only model) – or static – or based on the requested resource. It’s up to you now.
While we were at it, we also enabled easy support for parameterized scopes like e.g. transaction:id since they are used for some recent APIs specs like FAPI of FHIR.
These changes will require some minor migration steps when upgrading to v4, but allows for more flexibility.
Also, the work we did is foundational for the next step in IdentityServer’s resource access story, which is supporting resource isolation – or IOW resource indicators. This will ship in the next major update – which will be around end of this year, so stay tuned.
I wrote up the conceptional bits in our updated docs. Please give it a try!