Resource Access in IdentityServer4 v4 and going forward

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.

IdentityServer3
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.

IdentityServer4 v1-v3
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.

IdentityServer4 v4
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!

This entry was posted in IdentityServer, OAuth. Bookmark the permalink.

4 Responses to Resource Access in IdentityServer4 v4 and going forward

  1. Jay P says:

    Great article, Dominick!

    Just had a read of https://identityserver4.readthedocs.io/en/latest/topics/resources.html

    One quick question, in the last section “API Resources” – Is it mandatory to have all 5 scopes [(1) invoice.read, (2) invoice.pay, (3) customer.read, (4) customer.contact, and (5) manage] defined in “GetApiScopes()” method in order to use them in “GetApiResources()” method? Or would they get generated automatically based on the structure of ApiResources [(1) invoices, and (2) customers]?

    Thank you,
    Jay

    • All scopes need to be defined first before they can be used.

      • Jay P says:

        Understood, and is it possible / OK to share scope from IdentiyResource (rather than API scope) and use it ApiResource?

        E.g.,
        “`
        public static IEnumerable IdentityResources()
        {
        return new List
        {
        new IdentityResources.OpenId(),
        new IdentityResources.Profile(),
        new IdentityResource
        {
        Name = “Admin”,
        UserClaims = { “IsAdmin” }
        }
        };
        }

        public static IEnumerable ApiResources()
        {
        return new List
        {
        new ApiResource
        {
        Name = “Admin.API”,
        UserClaims = { “IsAdmin” },
        Scopes = { “Admin” }
        }
        };
        }
        “`

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s