Typed claims in ASP.Net Core 2.1

Hello and Welcome 🙂

Today I want to discuss about how we can use claims following a typed approach, this topic came about from a bug that was encountered during a code review for an application.

As such I wanted to find a way of mitigating such issues in the future by using concrete classes and the rarely used functionalities of implicit casting.

But first off, let’s look at what Claims are and how they are used.

The github repository for the examples in this post can be found here.

Table of contents:

What are claims?

If we look at the common definition for a claim in the context of authorization or identity, then a claim is a statement about a user or a role that is made by an application.

The common example for a claim, as seen in the wikipedia article, states that you can imagine your system as being a night club bouncer, and your user has a driver license, which has been released by an authorized third party, that driver licence states a few claims about our user such as their date of birth, which then the bouncer can verify that their date of birth meets the criteria (be over 18 years old) and that the license has been emitted by the authorizing party.

Based on the analogy previously described, a claim can be issued by other trusted systems, and they serve as meta-data for a specific user, or in some cases for a specific role. This makes claims a lot more composable than a user just having roles to describe their permissions or just using role-based approaches.

In short, a claim is a piece of meta-data or attributes of a user that claims something about the user and that claim is issued by some party, it’s up to the system to determine if that party is trusted or not.

How to create claims in ASP.Net Core 2.1

Now we’re going to look at how to manipulate claims for both users and roles.

If you’re building an ASP.Net Core application then you most likely will be using the Identity services provided by the library, which is a wrapper that adds several classes to the dependency injection container (Service provider). The class we are most interested in is UserManager<T>. Where T represents our user entity type respectively.

For us to use the UserManager we will need to inject it into the classes we want to use them in (several topics on this subject can be found in previous posts). Once we have our instance of the UserManager we can manipulate the claims by adding, removing, replacing claims as per documentation.

To create a claim we will need to create an instance new Claim("ClaimType", "ClaimValue"). Afterward using this instance we can add it to users, or update existing claims.

More information about all the constructor overloads for claims can be found here. But as we can see the claim type and the claim values are string based, which brings us to our current topic.

Our custom claim

So for this example, I created a class called UserCurrentDateTimeClaim that would represent a concrete claim I want to work within the example application. The class definition is as follows:

using System;

namespace TypedClaims.Controllers
{
    class UserCurrentDateTimeClaim
    {
        private readonly DateTime _dateTimeValue;

        public UserCurrentDateTimeClaim(DateTime dateTimeValue)
        {
            _dateTimeValue = dateTimeValue;
        }
    }
}

The point to illustrate here is the fact that our custom claim can only receive a DateTime instance, of course we could create claims as complex or as simple as required.

Now we need to have this class be able to pass off as a claim so that we can add it to a user without creating adaptors and other complex conversion mechanisms. So we will add an additional method that will implicitly cast out custom claim to a system claim.

using System;
using System.Security.Claims;

namespace TypedClaims.Controllers
{
    class UserCurrentDateTimeClaim
    {
        private readonly DateTime _dateTimeValue;

        public UserCurrentDateTimeClaim(DateTime dateTimeValue)
        {
            _dateTimeValue = dateTimeValue;
        }

        public static implicit operator Claim(UserCurrentDateTimeClaim userCurrentDateTimeClaim)
        {
            return new Claim(nameof(UserCurrentDateTimeClaim), userCurrentDateTimeClaim._dateTimeValue.ToString());
        }
    }
}

The implicit operator will let our system know how to convert our custom class into a Claim type. So now we can add this claim to a user like this await userManager.AddClaimAsync(currentUser, new UserCurrentDateTimeClaim(DateTime.Now));.

The benefit of this approach is that we have a consistent way of adding a specific claim to a user that will respect the type of the data we want to store, the name of the ClaimType and any other additional claim information we’re interested in like issuers.

Of course if our claim has a bit more validation logic in it, or methods that work with the underlying stored type, we might also want to convert it back from a claim to out custom type, so we will add another conversion method that will the the reverse.

using System;
using System.Security.Claims;

namespace TypedClaims.Controllers
{
    class UserCurrentDateTimeClaim
    {
        private readonly DateTime _dateTimeValue;

        public UserCurrentDateTimeClaim(DateTime dateTimeValue)
        {
            _dateTimeValue = dateTimeValue;
        }

        public static implicit operator Claim(UserCurrentDateTimeClaim userCurrentDateTimeClaim)
        {
            return new Claim(nameof(UserCurrentDateTimeClaim), userCurrentDateTimeClaim._dateTimeValue.ToString());
        }

        public static implicit operator UserCurrentDateTimeClaim(Claim claim)
        {
            return new UserCurrentDateTimeClaim(DateTime.Parse(claim.Value));
        }
    }
}

This way, once we have the claim we’re looking for (and we will see an example of that) we can convert it back to our own custom type and act upon it.

Example

With the custom claim class wrote before, I created a Post action in the example application that makes use of out custom claim.

public async Task AddUpdateDateClaim([FromServices]UserManager userManager)
        {
            var currentUser = await userManager.GetUserAsync(HttpContext.User);
            //tried it and we cannot convert directly into our own type on this line so first we need to retrieve the stored claim then switch it to our own implementation
            Claim updatedClaim = (await userManager.GetClaimsAsync(currentUser)).FirstOrDefault(claim => claim.Type == nameof(UserCurrentDateTimeClaim)); 
            if (updatedClaim is null)
            {
                await userManager.AddClaimAsync(currentUser, new UserCurrentDateTimeClaim(DateTime.Now));
            }
            else
            {
                UserCurrentDateTimeClaim exampleOfConvertingToCustomType = updatedClaim; // here we have the stored claim converted back to our own type
                await userManager.ReplaceClaimAsync(currentUser, exampleOfConvertingToCustomType,
                    new UserCurrentDateTimeClaim(DateTime.Now));
            }
            return RedirectToAction("Index");
        }

Conclusion

I hope you enjoyed my approach to using typed claims for eliminating the issues created by having claims stored as strings both for type and value.

With this approach you could even save object in JSON or binary format and just serialize and deserialize them, and as long as the system is configured properly (thinking of json serialization options) and the stored value has not been tampered by other means, then you should have a consistent way of switching to and from your own claim classes.

As stated at the start, the

Thank you and see you next time 😀


4 thoughts on “Typed claims in ASP.Net Core 2.1

  1. I used to be more than happy to seek out this web-site.I wanted to thanks in your time for this wonderful read!! I definitely enjoying every little little bit of it and I’ve you bookmarked to check out new stuff you weblog post.

    Like

Leave a comment