This article discusses claims transformation in .NET 6, a technique for adding custom claims to a user's identity for authorization purposes.
Abstract
The article begins by explaining the need for authorization in addition to authentication and the importance of keeping the two separate. It introduces the concept of claims transformation, which allows for the addition of custom claims to a user's identity. The article then describes the default claims available for authorization and how to use the IClaimsTransformation interface to add custom claims. The author also discusses the use of policies to authorize based on custom claims and the considerations and potential drawbacks of using claims transformation.
Opinions
The author suggests that mixing business and authorization logic can lead to more complex and less secure code.
The author recommends using policies to implement authorization scenarios and avoid duplicating logic.
The author acknowledges that claims transformation can introduce a performance penalty and an attack vector if an attacker gains access to the data source containing the custom claims.
The author suggests that using claims transformation can provide a more flexible and extendable authorization system.
The author provides a TLDR summary of the main points of the article.
The author provides links to additional resources for further reading.
The author promotes an AI service at the end of the article.
Claims Transformation in .NET 6
OAuth2 is a great protocol to authenticate people. And it does just that: Authentication. So.. What about authorization?
Implementing authorization in an API is pretty straightforward. And there are several ways to do it. In many projects, authorization and business logic tend to get mixed up. As a result, the code of the average, simple API endpoint gets more complex. And as a result, features get harder to implement and the application becomes less secure. So, needless to say: Don’t mix the two. But how do you do that?
To authorize means to apply a policy to a person in the context of him/her trying to access a resource. To be able to apply a policy that makes sense in your business context, you’ll probably need relevant domain-specific information about the person. But an access_token doesn’t contain that information by default. So, assuming we don’t want to put that information in the token, where do we put that? And how would that work?
Default claims you can use for authorization
When a user has authenticated and invokes an API endpoint with his/her access token, ASP.NET turns the token into a ClaimsIdentity. This ClaimsIdentity is available in your controller when you type:
Claims transformation
Say you are offering a SaaS product online. You would likely want to authorize someone based on his or her license. But, as you can see, such information is not available in the default claims.
Microsoft has support for this scenario out of the box. You can enrich claims on the fly (as you can read here). This concept is known as claims transformation. (In previous versions of .NET, this concept was known as claims augmentation.)
When you’re applying claims transformation, this is what the process of authenticating and authorizing looks like:
This is how authorization works with claims transformation.
There are several challenging bits in this diagram. This article focuses on parts 3 and 4.
The IClaimsTransformation interface
Microsoft has created a solution for the third step in the diagram: The IClaimsTransformation interface. By implementing it, you can easily add extra claims to the user his default claims. A simple implementation of the IClaimsTransformation interface might look somewhat like this:
And in your program.cs, add this line:
Registering the IClaimsTransformation class in the program.cs should be sufficient to make it work. Based on this registration, .NET will magically use this class to add your extra claims to the user’s ClaimsIdentity.
Use Policies to authorize based on your custom claims
Say you’ve used your implementation of IClaimsTransformation to add a claim:
"license":"premium"
A way to implement authorization with this custom claim would be:
This works. But it’s horrible:
This implementation mixes business- and authorization logic.
Before you know it, you’ll end up duplicating this logic all over the place.
An easier approach would be something that looks like this:
To make this work, we need to define the PremiumLicensesOnly policy. This can be done using Policies. Policies are an extendible feature in .NET that can be used to implement very complex authorization scenarios. You can register a simple policy in the program.cs, like so:
Considerations
Claims transformation is great. But there are a couple of things to consider when you are considering this approach:
Every API call will execute a query to a data source to get the custom claims. That’s a performance penalty.
You’re introducing an attack vector: If an attacker manages to obtain access to the data source that contains the custom claims, the attacker might be able to use the data source to elevate his/her privileges.
TLDR
By default, authenticating with OAuth2 results in a series of generic identity claims. This might not be sufficient to authorize a person.
It is possible to add more claims to a person's ClaimsIdentity on the fly by implementing the IClaimsTransformation interface that is a default part of .NET.
To verify claims, implement a so-called Policy. Policies are a standard .NET feature that is very extendible. Use it to prevent mixing business- and authorization logic.