ASP.NET Core Identity — Authentication and Authorization Explained
ASP.NET Core Identity is a membership system that handles user registration, login, password hashing, role management, and claims-based authorization — all integrated with Entity Framework Core.
What You’ll Learn
You’ll master user registration and login, role and claims management, JWT token authentication, and OAuth provider integration (Google, Facebook). You’ll build a complete Identity setup with JWT auth.
Why Identity Matters
Authentication is the security foundation for every web application. ASP.NET Core Identity handles the hard parts — password hashing, account lockout, token validation — so you don’t have to. At DodaTech, Identity-based auth protects DodaZIP cloud sync and Durga Antivirus Pro subscription management.
Identity Learning Path
flowchart LR
A[Entity Framework] --> B[ASP.NET Core Identity]
B --> C{You Are Here}
C --> D[Blazor]
C --> E[.NET MAUI]
style C fill:#f90,color:#fff
Setting Up Identity
First, install the package and configure services:
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer// Program.cs
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("Default")));
builder.Services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<AppDbContext>()
.AddDefaultTokenProviders();
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
};
});User Registration and Login
[ApiController]
[Route("api/auth")]
public class AuthController : ControllerBase
{
private readonly UserManager<IdentityUser> _userManager;
private readonly SignInManager<IdentityUser> _signInManager;
private readonly IConfiguration _config;
public AuthController(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager,
IConfiguration config)
{
_userManager = userManager;
_signInManager = signInManager;
_config = config;
}
[HttpPost("register")]
public async Task<IActionResult> Register([FromBody] RegisterDto dto)
{
var user = new IdentityUser
{
UserName = dto.Email,
Email = dto.Email
};
var result = await _userManager.CreateAsync(user, dto.Password);
if (!result.Succeeded)
return BadRequest(result.Errors);
return Ok(new { Message = "User created successfully" });
}
[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] LoginDto dto)
{
var user = await _userManager.FindByEmailAsync(dto.Email);
if (user == null)
return Unauthorized("Invalid credentials");
var result = await _signInManager.CheckPasswordSignInAsync(
user, dto.Password, lockoutOnFailure: true);
if (result.IsLockedOut)
return Unauthorized("Account locked. Try again later.");
if (!result.Succeeded)
return Unauthorized("Invalid credentials");
var token = await GenerateJwtToken(user);
return Ok(new { Token = token });
}
private async Task<string> GenerateJwtToken(IdentityUser user)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, user.Id),
new Claim(ClaimTypes.Email, user.Email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
};
var roles = await _userManager.GetRolesAsync(user);
claims.AddRange(roles.Select(r => new Claim(ClaimTypes.Role, r)));
var key = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: _config["Jwt:Issuer"],
audience: _config["Jwt:Audience"],
claims: claims,
expires: DateTime.UtcNow.AddHours(24),
signingCredentials: credentials
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}Roles and Claims
Roles group users for coarse authorization. Claims carry specific permissions:
// Creating roles
var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
await roleManager.CreateAsync(new IdentityRole("Admin"));
await roleManager.CreateAsync(new IdentityRole("User"));
// Assigning roles
await _userManager.AddToRoleAsync(user, "Admin");
// Custom claims
await _userManager.AddClaimAsync(user, new Claim("Permission", "CanDeletePosts"));
await _userManager.AddClaimAsync(user, new Claim("Department", "Engineering"));Protecting Endpoints
[ApiController]
[Route("api/admin")]
public class AdminController : ControllerBase
{
[HttpGet("dashboard")]
[Authorize(Roles = "Admin")] // Role-based
public IActionResult GetDashboard()
{
return Ok("Admin dashboard data");
}
[HttpPost("delete-user")]
[Authorize(Policy = "CanDeleteUsers")] // Policy-based
public IActionResult DeleteUser(string userId)
{
return Ok("User deleted");
}
}
// Registering policies with claims
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("CanDeleteUsers", policy =>
policy.RequireClaim("Permission", "CanDeletePosts"));
options.AddPolicy("EngineeringOnly", policy =>
policy.RequireClaim("Department", "Engineering"));
});OAuth Providers
Integrate Google, Facebook, or Microsoft authentication:
dotnet add package Microsoft.AspNetCore.Authentication.Googlebuilder.Services.AddAuthentication()
.AddGoogle(options =>
{
options.ClientId = builder.Configuration["Google:ClientId"];
options.ClientSecret = builder.Configuration["Google:ClientSecret"];
})
.AddFacebook(options =>
{
options.AppId = builder.Configuration["Facebook:AppId"];
options.AppSecret = builder.Configuration["Facebook:AppSecret"];
});Common Mistakes Beginners Make
1. Storing Passwords in Plain Text
Identity hashes passwords with PBKDF2 by default. Never store raw passwords. Never disable password hashing.
2. Not Using HTTPS in Production
Tokens and credentials sent over HTTP are intercepted by anyone on the network. Always enforce HTTPS.
3. Missing Token Validation Parameters
Without validating ValidateLifetime, expired tokens are accepted. Without ValidateIssuer, tokens from any server are valid.
4. Locking Users Without Lockout Configuration
Default lockout locks after 5 failed attempts for 5 minutes. Customize Account.Lockout in Identity options.
5. Storing JWTs in Local Storage
Browser local storage is accessible via XSS. Store tokens in HttpOnly cookies or memory.
6. Ignoring CSRF with Cookie Auth
When using cookie authentication (not JWT), add anti-forgery tokens to forms. Blazor Server handles this automatically.
7. Not Refreshing Tokens
JWT tokens expire. Implement a refresh token endpoint that issues new tokens without re-authentication.
Practice Questions
1. What does UserManager<T> handle?
User creation, password management, email confirmation, phone management, and role assignment.
2. What is the difference between roles and claims?
Roles are broad categories (Admin, User). Claims are specific permissions (CanDeletePosts, Department=Engineering).
3. What does [Authorize(Roles = "Admin")] do?
It restricts the endpoint to users who belong to the “Admin” role. Unauthorized users get a 401 response.
4. Why use JWT over cookie authentication?
JWT works across APIs, mobile apps, and SPAs without CSRF concerns. Cookies are simpler for traditional MVC apps.
5. Challenge: Implement password reset.
Add a ForgotPassword endpoint that generates a token and emails it. Add a ResetPassword endpoint that validates the token and changes the password.
Mini Project: Secure API with Identity
Build a secure task management API:
- Register/login with JWT (as shown above)
[Authorize]on all task endpoints- Admin role can view all tasks. User role views only their tasks
- Add a
CreatedByUserIdclaim on each task - Add a policy:
TaskOwnerPolicy— only the creator or admin can edit/delete
FAQ
What’s Next
Congratulations on completing this Identity tutorial! Here’s where to go from here:
- Practice daily — Implement one auth flow per day
- Build a project — Secure a full-stack app with Identity
- Explore related topics — OAuth 2.0 flows, OpenID Connect
- Join the community — Share your auth implementations and get feedback
Remember: every expert was once a beginner. Keep securing!
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro