How to add extra user claims in ASP.NET Core web-app
Tags: aspnetcore, aspnetidentity, claims
Published: 2019-07-26 09:09:03


## Introduction

ASP.NET Core has sufficiently developed tools for implementing authentication and authorization mechanisms in your projects. These tools are available out-of-the-box and rather simple in configuring. Even the starting web-project created with Visual Studio wizard already includes all the necessary parts of the authorization subsystem (Registration/Login/User Profile forms, Reset password procedure, etc.)

However, some at first glance, simple tasks require a deeper understanding of the internal structure of ASP.NET Core Identity. 

In this article, we will discuss one of these tasks and suggest a solution to it using the [claims-based approach](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/claims).

## Problem

Let's suppose we created a new ASP.NET Core project using one of the default templates and chose "Individual user account" option for "Authentication".

![ASP.NET Identity new project](https://korzh.com/static/blogs/net-tricks/anc22-add-extra-claim01.png "ASP.NET Core - new web-app project with an authentication")

Now when we start that newly created project and register new user we will see something like `Hello YourEmailAddress@YourCompany.com` in the top right part of the index web-page.

Obviously, such kind of greeting is useless in a real-world application and you would like to see the name of the currently logged user there instead (e.g. `Hello John Doe`).  
Let's figure out how to do it.

## Solution

Here we guess you are already familiar with the claims and [claims-based approach](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/claims) for authorization used in ASP.NET Core Identity. If not - please read [ASP.NET Core Security](https://docs.microsoft.com/en-us/aspnet/core/security/) article first.

To achieve our goal we need to do 2 things:

 1. Add necessary information to the list of the claims attached to the user's identity.
 2. Have a simple way of getting that info when needed.

But before implementing these two tasks we will need to add a new ContactName field to our model class and update our registration and user management pages accordingly.

## 0. Preparations

Before we can add a new claim to a user object (the one you can access via `HttpContext.User`) we need a place to store that additional info somewhere.
Here I am going to describe how to get this done for a new ASP.NET Core project built by a default template.

If you work on some real-world project - most probably you already did similar changes before. 
In this case, you can skip this "preparations" section and move right to the next one.

### 1. New ApplicationUser class

Add a new  `ApplicationUser` class with `ContactName' property: 


    public class ApplicationUser : IdentityUser
    {
        public string ContactName { get; set; }
    }

Of course, you can add more properties to store some additional information with the user account.
For example: `FirstName`, `LastName`, `Country`, `Address`, etc. All of them can be placed to claims the same way as `ContactName` we discuss here.

### 2. Replace `IdentityUser` with `ApplicationUser`  

Now you need to replace `IdentityUser` with `ApplicationUser` everywhere in your project.

The default ASP.NET Core template uses predefined `IdentityUser` type everywhere. 
Since we what to use `ApplicationUser` instead of it - we need to search for all inclusions of `IdentityUser` in your project and replace with `ApplicationUser`.

It will include your DbContext class, one line in `Startup` class (in `ConfigureServices` method) and two lines with `@inject` directives in `_LoginPartial.cshtml` view.

Here is how your new `ApplicationDbContext` class will look like after that:


	public class ApplicationDbContext : IdentityDbContext<ApplicationUser, IdentityRole, string>
	{
		public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
			: base(options)
		{
		}
	}


### 3. Update your database.

Now you need to add a new migration and then update your DB.
Just run the following 2 commands from your project's folder:


    dotnet ef migrations add AddUserContactName

    dotnet ef database update


### 4. Update "User Profile" page

Finally, we will need to add our new field to the "User Profile" page to make it possible for users to modify it.

The default ASP.NET Core template uses all identity-related pages directly from a special Razor UI library (`Microsoft.AspNetCore.Identity.UI`).
The good news is: we can override any of those pages if we want. Here are the steps we need to do:

1. Right-click on your project in VS and select Add | New Scaffolding item.

2. In the "Add Scaffold" dialog select `Identity` on the left side tree and then `Identity` in the main list and click "Add".

3. In the dialog that appears select only `Account\Manage\Index` page and then click on "Add" as well.
When the process is finished you will find a new page 'Index.cshtml' in `Areas/Identity/Pages` folder.

4. After that make the following changes to that `Index` page:

In the Index.cshtml itself add the following piece of markup right before `update-profile-button` button.


    <div class="form-group">
      <label asp-for="Input.ContactName"></label>
      <input asp-for="Input.ContactName" class="form-control" />
      <span asp-validation-for="Input.ContactName" class="text-danger"></span>
    </div>


Then, in the code-behind file `Index.cshtml.cs` we need to modify the view model:

    public class InputModel
    {
        .   .   .   .   .   .

        public string ContactName { get; set; }
    }


then the `OnGetAsync` method:

	public async Task<IActionResult> OnGetAsync()
	{
		.   .   .   .   .   .
		
		Input = new InputModel
		{
			Email = email,
			PhoneNumber = phoneNumber,
			ContactName = user.ContactName //add this line
		};

		.   .   .   .   .   .
		
	}

and the `OnPutAsync`:

	public async Task<IActionResult> OnPostAsync()
	{
		.    .    .    .    .    .    .

		if (Input.ContactName != user.ContactName) {
			user.ContactName = Input.ContactName;
			await _userManager.UpdateAsync(user);
		}

		await _signInManager.RefreshSignInAsync(user);
		StatusMessage = "Your profile has been updated";
		return RedirectToPage();
	}

So, after all the changes described above your User Profile page after that registration will look like this:

![User Profile form with ContactName field](https://korzh.com/static/blogs/net-tricks/anc22-add-extra-claim02.png "User Profile form with ContactName field")

Now, all the preparations are finished we can return back to our main task.


## 1. Adding the contact name to the claims
A funny thing: the main task is much easier than all the preparations we made before. :)
Moreover, it became even easier because of some changes in version 2.2 of ASP.NET Core (in comparison with version 2.0 as [we described before](https://korzh.com/blogs/net-tricks/aspnet-identity-store-user-data-in-claims) )

There are only two simple steps:

### Create own claims principal factory

We need an implementation `IUserClaimsPrincipalFactory` which will add necessary information (`ContactName` in our case) to the user claims. 
The simplest way to do it - is to derive our new class from the default implementation of `IUserClaimsPrincipalFactory` and override one method: `GenerateClaimsAsync`:

	public class MyUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser>
	{
		public MyUserClaimsPrincipalFactory(
			UserManager<ApplicationUser> userManager,
			IOptions<IdentityOptions> optionsAccessor)
			: base(userManager, optionsAccessor)
		{
		}

		protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user)
		{
			var identity = await base.GenerateClaimsAsync(user);
			identity.AddClaim(new Claim("ContactName", user.ContactName ?? "[Click to edit profile]"));
			return identity;
		}
	}

### Register new class in DI container

Then we need to register our new class in the dependency injection container.
The best way for that - to use `AddClaimsPrincipalFactory` extension method: 

	public void ConfigureServices(IServiceCollection services) 
	{
		.     .     .     .      .
		services.AddDefaultIdentity<ApplicationUser>()
			.AddDefaultUI(UIFramework.Bootstrap4)
			.AddEntityFrameworkStores<ApplicationDbContext>()
			.AddClaimsPrincipalFactory<MyUserClaimsPrincipalFactory>();  //<---- add this line
	}

## 2. Accessing new claim from the views

Now we have a new claim associated with our user's identity. That's fine. But how we can get it and render on our view(s)?
Easy. Any view in your application has access to `User` object which is an instance of `ClaimsPrincipal` class.

This object actually holds the list of all claims associated with the current user and you can call its `FindFirst` method to get the necessary claim and then read the `Value` property of that claim.

So, we just need to open `_LoginPartical.cshtml` file in `Pages/Shared/` (or `Views/Shared/`) folder and replace the following line:


    <a asp-area="" asp-controller="Manage" asp-action="Index" title="Manage">Hello @User.Identity.Name!</a>

with this one:

    <a asp-area="" asp-controller="Manage" asp-action="Index" title="Manage">Hello @(User.FindFirst("ContactName").Value)!</a>


Now you instead of something like `Hello john.doe@yourcompany.com` at the top of your web-page you should see something like this:

![ASP.NET Identity contact name](https://korzh.com/static/blogs/net-tricks/anc22-add-extra-claim03.png "ASP.NET Core - showing user's contact name instead of email")

That's all for now. Enjoy!

> The article was originally posted on [Korzh.com blog](https://korzh.com/blogs/net-tricks/add-extra-user-claims-aspnet-core-webapp).