Cloud Quality Cloud Pricing

Mastering ASP.NET Core Identity: Your Complete Guide to Authentication & Authorization

ASP.NET Core Identity is the built-in membership system for web applications – think of it as your app’s personal security toolkit. It handles user registration and login (forms authentication) as well as storing and securing user accounts, passwords, profile data, roles, and claims. Under the hood, Identity uses Entity Framework Core to create tables (like AspNetUsersAspNetRoles, etc.) in a database (usually SQL Server by default) to persist all this information. It even supports modern security features out of the box – like two-factor authentication and social logins (Google, Facebook, Twitter, etc.) – so you can give your users a polished, secure login experience without starting from scratch. In short, ASP.NET Core Identity is the go-to way to add robust authentication (who you are) and authorization (what you can do) to your ASP.NET Core apps.

  • Easy login/registration UI: Identity provides ready-to-use Razor Pages or MVC pages for registering and logging in users.
  • User & password management: It handles creating users and hashing their passwords for you, and can store extra profile info in your database.
  • Roles and claims support: Built-in support for roles (like “Admin”) and claims (key-value user data) makes fine-grained authorization straightforward
  • Security tokens: It issues tokens for email confirmation, password resets, and supports 2FA (time-based codes).
  • External login providers: You can hook up Google, Microsoft, Facebook, etc. in minutes.

What Is ASP.NET Core Identity (the Framework)?

ASP.NET Core Identity (often just called Identity) is a framework for managing user authentication and authorization in ASP.NET Core applications. In essence, it’s a membership system that you plug into your app so you don’t have to build login and account management from the ground up. When you enable Identity, it adds APIs for user registration, login, logout, password hashing, email confirmation, account lockout after bad logins, and more. It also creates a set of database tables (via EF Core migrations) like AspNetUsersAspNetRoles, and AspNetUserClaims to store all user and role information.

Importantly, Identity is very flexible. By default it uses a SQL Server (or SQLite) database via Entity Framework Core, but you can swap in any store (Azure Tables, MongoDB, etc.) by implementing the appropriate stores. Regardless of the store, the Identity framework exposes a clean API (UserManager, SignInManager, RoleManager, etc.) that your code calls to create users, check passwords, manage roles, and issue claims. As Microsoft notes, “Identity is typically configured using a SQL Server database to store user names, passwords, and profile data. Alternatively, another persistent store can be used”. In other words, Identity provides the plumbing for user data; you focus on your app logic.

So what is Identity used for? In practice, it’s the “glue” for authentication/authorization tasks: authenticating logins (forms or external), authorizing access (via roles/claims/policies), and managing user data. For example, if you need to let users register and log in, assign them roles like “Admin” or “Editor”, and then lock certain pages to specific roles, Identity handles most of this for you. It even comes with templates for the UI. As Tutorialspoint puts it, Identity “allows us to add features where users can register and log in with a local password… [and] supports two-factor authentication, third-party identity providers and other features”. In short, whenever you see a login form or an <strong>[Authorize]</strong> attribute in an ASP.NET Core app, Identity is likely powering it.

Setting Up Identity in Your ASP.NET Core App

Enabling Identity in a project is straightforward. In your Program.cs (or Startup.cs) you register Identity services with the dependency injection container. For example, a common setup is:

csharp

builder.Services.AddDefaultIdentity<IdentityUser>(options => {/* optional options */})
    .AddEntityFrameworkStores<ApplicationDbContext>();

This call does several things: it registers the core Identity services for managing users of type
IdentityUser, configures things like password policies, and tells Identity to use your ApplicationDbContext (an EF Core DbContext) to store user data. The .AddEntityFrameworkStores<ApplicationDbContext>() part hooks up the default user stores to your database. In code:

  • AddDefaultIdentity<IdentityUser>() sets up a basic Identity system with sensible defaults (cookie authentication, password requirements, etc.).
  • AddIdentity<TUser, TRole>() (instead of AddDefaultIdentity) lets you also include roles in one shot.
  • AddEntityFrameworkStores<YourDbContext>() tells Identity to use Entity Framework Core (using your DbContext) as the data store.

For example, Microsoft’s docs show:

csharp

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();

The above configures Identity and also requires email confirmation before signing in. Under the covers this will create the Identity tables when you apply migrations.

If you plan to use roles (e.g. “Admin” or “Manager”), you need to add that explicitly. By default, AddDefaultIdentity does not include role support. You have two main options: call AddIdentity<IdentityUser, IdentityRole>() or simply chain .AddRoles<IdentityRole>(). As NimblePros blogger Jeremiah Cooper notes, “Role services are not added by default but can be added with AddRoles()”. Similarly, Microsoft’s docs show:

csharp

builder.Services.AddDefaultIdentity<IdentityUser>(...)
        .AddRoles<IdentityRole>();

In other words, add AddRoles<IdentityRole>() before calling .AddEntityFrameworkStores(…) so that the role-related services (like RoleManager) are set up correctly. Once configured, you have access to RoleManager<IdentityRole> and can programmatically create roles or assign them to users.
After registering Identity in services, you also need to make sure the middleware runs. In Program.cs, use:

csharp

app.UseAuthentication();
app.UseAuthorization();

These enable the authentication and authorization layers. Now your app can sign users in/out and check their credentials.

Scaffolding and Customizing the Identity UI

By default, Identity comes with a ready-made Razor Class Library for UI pages (Login, Register, etc.), but you might want to customize them. To do that, you scaffold the Identity pages into your project. You have two main approaches:

  • Visual Studio (GUI): Right-click your project → Add > New Scaffolded Item… → choose Identity. Then pick which pages to override (Login, Register, etc.), select your existing _Layout if you have one, and provide your data context and user class. Finally click Add. Visual Studio will add an Areas/Identity/Pages folder with Razor pages for all the chosen identity screens. For example, C# Corner shows adding Identity via the New Scaffolded Item dialog (select Identity, then specify DbContext and user class)

  • .NET CLI: You can also use the ASP.NET code generator. First install the tool if needed:
csharp

dotnet tool install --global dotnet-aspnet-codegenerator

Then run a command like:

css

dotnet aspnet-codegenerator identity --useDefaultUI --force

This scaffolds the default UI into your project (the –useDefaultUI flag tells it to use the built-in pages, –force overwrites any existing). There are other switches (e.g. –layout, –dbContext to specify your classes). The official docs give an example to scaffold with the default UI:

In the project folder, run the Identity scaffolder with the options you want. To scaffold Identity with the default Identity UI and the minimum number of files, run the following command:

dotnet aspnet-codegenerator identity --useDefaultUI

After scaffolding, you’ll see new Razor pages (e.g. under Areas/Identity/Pages/Account for Login, Register, etc.). You can edit these files to change the look or add fields. Don’t forget to add an Entity Framework migration and update the database after scaffolding, because Identity needs to create its tables. For example, run:

bash

dotnet ef migrations add CreateIdentitySchema
dotnet ef database update

This applies the migrations and creates tables like AspNetUsersAspNetRoles, etc., in your database. Once migrated, your app is ready to register and log in users with the pages you customized.

Roles in ASP.NET Core Identity

Roles are a key part of authorization. A role is simply a label (like “Admin”, “Editor”, “Manager”) that you can assign to users. Once a user has a role, you can restrict access to parts of your app based on that role. ASP.NET Core Identity supports role-based authorization out of the box.

Enabling Roles

As mentioned, you enable roles in your service configuration by calling .AddRoles<IdentityRole>() when setting up Identity. For example:

csharp

builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
       .AddEntityFrameworkStores<ApplicationDbContext>();

or

csharp

builder.Services.AddDefaultIdentity<IdentityUser>()
       .AddRoles<IdentityRole>()
       .AddEntityFrameworkStores<ApplicationDbContext>();

The official docs note that AddRoles<IdentityRole>()  “must be added to Role services” in Program.cs. Once that is done, you can inject RoleManager<IdentityRole> and UserManager<IdentityUser> (or your ApplicationUser type) via DI.

Creating and Assigning Roles

To create a role programmatically, use the RoleManager in your code or a seed method. For example:

csharp

var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
if (!await roleManager.RoleExistsAsync("Admin"))
{
    await roleManager.CreateAsync(new IdentityRole("Admin"));
}

Now the “Admin” role exists in your database. To assign a role to a user, use UserManager:

csharp

var userManager = serviceProvider.GetRequiredService<UserManager<IdentityUser>>();
var user = await userManager.FindByEmailAsync("[email protected]");
await userManager.AddToRoleAsync(user, "Admin");

This will insert a record into the AspNetUserRoles table linking that user to the Admin role. You can also remove roles with RemoveFromRoleAsync.

If you forget to enable roles (e.g. by not calling AddRoles first), you may get runtime errors when trying to use RoleManager or UserManager.AddToRoleAsync. The NimblePros blog recounts this pitfall: “If you’ve used identity in the past, Roles were always included automatically. Now, however, they’re not enabled by default!” and shows how calling AddRoles<IdentityRole>() before the EF store registration fixes the issue.

Retrieving User Roles

Once roles are assigned, you often need to check what roles a user has. ASP.NET Core Identity provides UserManager.GetRolesAsync(user), which returns a list of role names for that user. For example:

csharp

var roles = await userManager.GetRolesAsync(user); 
// roles is an IList<string> like ["Admin", "User"]

Alternatively, in a controller or Razor page with a signed-in user, you can use the
ClaimsPrincipal methods:

  • User.IsInRole(“Admin”) to check a specific role.
  • User.FindAll(ClaimTypes.Role) to enumerate all role claims.

Behind the scenes, GetRolesAsync and IsInRole look at the role claims in the user’s authentication cookie, which were populated from the database.

Claims in ASP.NET Core Identity

Beyond roles, claims are another way to store information about a user. A claim is simply a (type, value) pair attached to the user’s identity. For example, a claim could say (“Department”, “Sales”) or (“IsEmployee”, “true”). Claims are extremely flexible and can represent anything about the user’s identity.

As Microsoft explains, a claim “is a name-value pair that represents what the subject is, not what the subject can do”. (Roles, by contrast, are about what a user can do, whereas other claims describe attributes like name, email, or permissions.) In practice, Identity creates some claims automatically (e.g. ClaimTypes.Name for the username, ClaimTypes.Email if provided). You can add your own claims to extend the user profile.

To add a claim to a user in code, use the UserManager.AddClaimAsync method. For example:

csharp

var claim = new Claim("FavoriteColor", "Blue");
await userManager.AddClaimAsync(user, claim);

This will attach that claim to the user’s record in the database (specifically the
AspNetUserClaims table). The docs simply state that AddClaimAsync(user, claim) “adds the specified claim to the user”. (Internally, Identity stores it in the UserClaims store, which by default is a DB table when using EF.)

Once a user has claims, they will be included in the user’s ClaimsPrincipal after login. You can access them via User.Claims in your controller or page. For example, to check the new claim above, use User.HasClaim(“FavoriteColor”, “Blue”). Claims are especially useful for fine-grained data like individual permissions or profile attributes that aren’t full “roles”. For instance, you could have a claim (“IsEmployee”, “true”) instead of making a whole “Employee” role

When using IdentityServer (see below), Identity will automatically include user claims in the identity tokens it issues. But even without IdentityServer, Identity’s claims are used for authorization decisions or personalizing UI (e.g. showing the user’s email).

Enforcing Roles and Policies

With roles and claims set up, you’ll often enforce authorization in your controllers or Razor Pages. The simplest approach is using the [Authorize] attribute with role names:

csharp

[Authorize(Roles = "Admin")]
public class AdministrationController : Controller
{
    public IActionResult Index() => View();
}

The above restricts the Administration pages to only users in the “Admin” role. You can list multiple roles as a comma-separated string (e.g. “Admin,Manager”) to allow either rolelea. Under the hood, ASP.NET Core checks the user’s role claims against the requirement. If the signed-in user isn’t in the required role, they’ll be denied access (usually redirected to a login or access-denied page).

You can also define authorization policies in Program.cs that require certain roles, and then use [Authorize(Policy = “AdminOnly”)]. For example:

csharp

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AdminOnly",
        policy => policy.RequireRole("Admin"));
});

Now you can decorate classes or methods with
[Authorize(Policy = “AdminOnly”)]. This is equivalent to requiring the Admin role but lets you centralize the role string in one place.

ASP.NET Core Identity, by default, reads the roles for the user from their claims (issued at login). The framework automatically includes roles in the authentication cookie. All you have to do is enable role services (as shown above) and use the [Authorize] attribute or policies. The middleware then “just works” to check and enforce those roles for you.

What Is IdentityServer, and How Does It Relate to Core Identity?

All the above is about ASP.NET Core Identity, which runs in your app and manages users for that app. IdentityServer (now Duende IdentityServer) is a related but distinct concept. It’s an OpenID Connect (OIDC) and OAuth 2.0 framework that turns your app into a centralized authentication server. In simpler terms, IdentityServer is used for Single Sign-On (SSO) and issuing tokens that can secure multiple apps and APIs.

Duende (IdentityServer) describes itself as “an OpenID Connect and OAuth 2.0 framework for ASP.NET Core”. This means it implements the industry-standard protocols (OIDC/OAuth2) so client apps (or browsers) can ask it to authenticate users and receive tokens (JWTs or others). You would use IdentityServer when you need an “authentication authority” that can serve many client apps. For example, a company with several internal applications might have one IdentityServer that employees log into, and then access various systems seamlessly.

IdentityServer is not part of Identity by default, but it often uses ASP.NET Core Identity as its user store. Duende provides integration packages like Duende.IdentityServer.AspNetIdentity that wire up IdentityServer to the Identity user database. In practice, setting up IdentityServer involves:

  • Creating a new ASP.NET Core host (usually a web app)
  • Adding the Duende IdentityServer NuGet package(s)
  • Configuring clients and resources (who can request tokens and what scopes)
  • Adding ASP.NET Core Identity for user accounts (the login UI)
  • Calling services.AddIdentity<YourUser,IdentityRole>() before AddIdentityServer() and then calling .AddAspNetIdentity<YourUser>() on the IdentityServer builder.

For example, the Duende quickstart shows this sequence:

In ConfigureServices, notice the necessary AddIdentity<ApplicationUser, IdentityRole>() calls… [they configure ASP.NET Core Identity]. Also notice the addition of the call to AddAspNetIdentity<ApplicationUser>()AddAspNetIdentity() adds the integration layer to allow IdentityServer to access the user data for the ASP.NET Core Identity user database… Note that AddIdentity() must be invoked before AddIdentityServer().”

Once configured, IdentityServer will use the ASP.NET Core Identity user store to authenticate users. Users can log in via Identity (the normal login pages), and then IdentityServer will issue the appropriate tokens (ID tokens, access tokens) including user claims and roles. IdentityServer then handles sign-on, and can secure APIs by validating those tokens.

In short, IdentityServer is for when you need OAuth/OIDC support and federation. It’s what you’d use instead of (or in addition to) things like Azure AD for handling login across systems. And you can wire it up to the familiar ASP.NET Core Identity for user data.

Summary and Next Steps

ASP.NET Core Identity is an essential part of many web projects. It saves you from hand-writing all the complex code for managing users, hashing passwords, and implementing login/logout flows. In this guide we’ve covered what Identity is, how to set it up, how to scaffold the UI, and how to work with roles and claims. We also touched on IdentityServer for more advanced scenarios.

Key takeaways for an ASP.NET developer:

  • Identity vs. IdentityServer: ASP.NET Core Identity is in-app user management (authentication/authorization). IdentityServer (Duende) is an external OAuth/OIDC server for SSO and token issuance.
  • Quick setup: Use AddDefaultIdentity or AddIdentity in Program.cs and scaffold the UI if needed. Run EF migrations to create the schema.
  • Roles & claims: Add roles by calling .AddRoles<IdentityRole>() and use UserManager.AddToRoleAsync() to assign roles. Get roles via GetRolesAsync(). Add custom claims via UserManager.AddClaimAsync().
  • Authorize: Apply [Authorize(Roles=”Admin”)] on controllers, or use policies for complex rules. Identity takes care of the cookie and claim principal for you.

An anecdote: many developers spend weeks debugging a home-rolled login system, not realizing ASP.NET Core Identity can do it out-of-the-box. By leveraging Identity (and occasionally IdentityServer), you free up time and gain battle-tested security features.

For deeper learning, check the official Microsoft docs and the Duende IdentityServer documentation. The ASP.NET Core templates (when you choose “Individual Accounts” or run dotnet new mvc –auth Individual) demonstrate how Identity wiring looks in real projects. Embrace Identity – and say goodbye to custom authentication headaches!

Happy coding and stay secure! (And remember, even developers need good identity management – let Identity do the heavy lifting.)