Learn ASP.NET Core authentication: Identity for user management, JWT bearer tokens, cookie authentication, and OAuth/OpenID Connect.
Authentication in ASP.NET Core verifies the identity of users. The framework supports ASP.NET Core Identity for user management, JWT bearer tokens for stateless APIs, cookie authentication for server-rendered apps, and OAuth/OpenID Connect for federated identity.
ASP.NET Core Identity provides user registration, login, password hashing, roles, and claims:
1// Program.cs - Identity Setup
2builder.Services.AddDbContext<ApplicationDbContext>(options =>
3 options.UseNpgsql(builder.Configuration.GetConnectionString("Default")));
4
5builder.Services.AddIdentity<ApplicationUser, IdentityRole>(options =>
6{
7 // Password settings
8 options.Password.RequiredLength = 8;
9 options.Password.RequireDigit = true;
10 options.Password.RequireUppercase = true;
11 options.Password.RequireNonAlphanumeric = true;
12
13 // Lockout settings
14 options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(15);
15 options.Lockout.MaxFailedAccessAttempts = 5;
16
17 // User settings
18 options.User.RequireUniqueEmail = true;
19 options.SignIn.RequireConfirmedEmail = true;
20})
21.AddEntityFrameworkStores<ApplicationDbContext>()
22.AddDefaultTokenProviders();
23
24// Custom User class
25public class ApplicationUser : IdentityUser
26{
27 public string FirstName { get; set; } = "";
28 public string LastName { get; set; } = "";
29 public DateTime DateOfBirth { get; set; }
30 public string ProfilePictureUrl { get; set; } = "";
31}
32
33// DbContext
34public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
35{
36 public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
37 : base(options) { }
38
39 protected override void OnModelCreating(ModelBuilder builder)
40 {
41 base.OnModelCreating(builder);
42 // Customize Identity tables
43 builder.Entity<ApplicationUser>().ToTable("Users");
44 builder.Entity<IdentityRole>().ToTable("Roles");
45 }
46}Configure JWT authentication for stateless API authorization:
1// JWT Configuration
2builder.Services.AddAuthentication(options =>
3{
4 options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
5 options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
6})
7.AddJwtBearer(options =>
8{
9 options.TokenValidationParameters = new TokenValidationParameters
10 {
11 ValidateIssuer = true,
12 ValidateAudience = true,
13 ValidateLifetime = true,
14 ValidateIssuerSigningKey = true,
15 ValidIssuer = builder.Configuration["Jwt:Issuer"],
16 ValidAudience = builder.Configuration["Jwt:Audience"],
17 IssuerSigningKey = new SymmetricSecurityKey(
18 Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]!))
19 };
20});
21
22// Token Generation Service
23public class TokenService
24{
25 private readonly IConfiguration _config;
26
27 public TokenService(IConfiguration config) => _config = config;
28
29 public string GenerateToken(ApplicationUser user, IList<string> roles)
30 {
31 var claims = new List<Claim>
32 {
33 new(ClaimTypes.NameIdentifier, user.Id),
34 new(ClaimTypes.Email, user.Email!),
35 new(ClaimTypes.Name, user.UserName!),
36 new("firstName", user.FirstName),
37 new("lastName", user.LastName)
38 };
39
40 claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
41
42 var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]!));
43 var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
44
45 var token = new JwtSecurityToken(
46 issuer: _config["Jwt:Issuer"],
47 audience: _config["Jwt:Audience"],
48 claims: claims,
49 expires: DateTime.UtcNow.AddHours(1),
50 signingCredentials: creds
51 );
52
53 return new JwtSecurityTokenHandler().WriteToken(token);
54 }
55
56 public RefreshToken GenerateRefreshToken()
57 {
58 return new RefreshToken
59 {
60 Token = Convert.ToBase64String(RandomNumberGenerator.GetBytes(64)),
61 Expires = DateTime.UtcNow.AddDays(7),
62 Created = DateTime.UtcNow
63 };
64 }
65}Cookie-based authentication stores session data in encrypted cookies:
1// Cookie Authentication Setup
2builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
3 .AddCookie(options =>
4 {
5 options.Cookie.Name = "MyApp.Auth";
6 options.Cookie.HttpOnly = true;
7 options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
8 options.Cookie.SameSite = SameSiteMode.Strict;
9 options.ExpireTimeSpan = TimeSpan.FromHours(24);
10 options.SlidingExpiration = true;
11 options.LoginPath = "/auth/login";
12 options.LogoutPath = "/auth/logout";
13 options.AccessDeniedPath = "/auth/access-denied";
14
15 options.Events = new CookieAuthenticationEvents
16 {
17 OnValidatePrincipal = async context =>
18 {
19 // Custom validation logic
20 var userService = context.HttpContext.RequestServices
21 .GetRequiredService<IUserService>();
22 var userId = context.Principal?.FindFirstValue(ClaimTypes.NameIdentifier);
23
24 if (userId != null && !await userService.IsUserActiveAsync(userId))
25 {
26 context.RejectPrincipal();
27 await context.HttpContext.SignOutAsync();
28 }
29 }
30 };
31 });
32
33// Sign-in with cookies
34[HttpPost("login")]
35public async Task<IActionResult> Login(LoginDto model)
36{
37 var user = await _userManager.FindByEmailAsync(model.Email);
38 if (user == null || !await _userManager.CheckPasswordAsync(user, model.Password))
39 return Unauthorized("Invalid credentials");
40
41 var claims = new List<Claim>
42 {
43 new(ClaimTypes.NameIdentifier, user.Id),
44 new(ClaimTypes.Email, user.Email!),
45 new(ClaimTypes.Name, user.UserName!)
46 };
47
48 var roles = await _userManager.GetRolesAsync(user);
49 claims.AddRange(roles.Select(r => new Claim(ClaimTypes.Role, r)));
50
51 var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
52 var principal = new ClaimsPrincipal(identity);
53
54 await HttpContext.SignInAsync(
55 CookieAuthenticationDefaults.AuthenticationScheme,
56 principal,
57 new AuthenticationProperties
58 {
59 IsPersistent = model.RememberMe,
60 ExpiresUtc = DateTimeOffset.UtcNow.AddDays(model.RememberMe ? 30 : 1)
61 });
62
63 return Ok(new { message = "Login successful" });
64}Integrate Google, GitHub, Azure AD, and other providers with OAuth 2.0 / OIDC:
1// OAuth Configuration - Google, GitHub
2builder.Services.AddAuthentication(options =>
3{
4 options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
5 options.DefaultChallengeScheme = GoogleDefaults.AuthenticationScheme;
6})
7.AddCookie()
8.AddGoogle(options =>
9{
10 options.ClientId = builder.Configuration["Auth:Google:ClientId"]!;
11 options.ClientSecret = builder.Configuration["Auth:Google:ClientSecret"]!;
12 options.Scope.Add("profile");
13 options.Scope.Add("email");
14 options.SaveTokens = true;
15
16 options.Events.OnCreatingTicket = async context =>
17 {
18 // Custom claim mapping
19 var email = context.Principal?.FindFirstValue(ClaimTypes.Email);
20 if (email != null)
21 {
22 var userService = context.HttpContext.RequestServices
23 .GetRequiredService<IUserService>();
24 var user = await userService.GetOrCreateExternalUserAsync(
25 context.Principal!, "Google");
26 // Add custom claims
27 var identity = context.Principal!.Identity as ClaimsIdentity;
28 identity?.AddClaim(new Claim("userId", user.Id));
29 }
30 };
31})
32.AddGitHub(options =>
33{
34 options.ClientId = builder.Configuration["Auth:GitHub:ClientId"]!;
35 options.ClientSecret = builder.Configuration["Auth:GitHub:ClientSecret"]!;
36 options.Scope.Add("user:email");
37 options.Scope.Add("read:user");
38});
39
40// OpenID Connect (Azure AD, Auth0)
41.AddOpenIdConnect("AzureAD", options =>
42{
43 options.Authority = builder.Configuration["AzureAd:Authority"];
44 options.ClientId = builder.Configuration["AzureAd:ClientId"];
45 options.ClientSecret = builder.Configuration["AzureAd:ClientSecret"];
46 options.ResponseType = OpenIdConnectResponseType.Code;
47 options.SaveTokens = true;
48 options.GetClaimsFromUserInfoEndpoint = true;
49 options.Scope.Add("openid");
50 options.Scope.Add("profile");
51 options.Scope.Add("email");
52
53 options.TokenValidationParameters = new TokenValidationParameters
54 {
55 NameClaimType = "name",
56 RoleClaimType = "roles"
57 };
58});
59
60// Controller for external auth
61[HttpGet("external-login/{provider}")]
62public IActionResult ExternalLogin(string provider, string? returnUrl = null)
63{
64 var redirectUrl = Url.Action("ExternalLoginCallback", new { returnUrl });
65 var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
66 return Challenge(properties, provider);
67}
68
69[HttpGet("external-login-callback")]
70public async Task<IActionResult> ExternalLoginCallback(string? returnUrl = null)
71{
72 var info = await _signInManager.GetExternalLoginInfoAsync();
73 if (info == null) return RedirectToAction("Login");
74
75 var result = await _signInManager.ExternalLoginSignInAsync(
76 info.LoginProvider, info.ProviderKey, isPersistent: false);
77
78 if (result.Succeeded)
79 return LocalRedirect(returnUrl ?? "/");
80
81 // Create new user if first time
82 var email = info.Principal.FindFirstValue(ClaimTypes.Email);
83 var user = new ApplicationUser { UserName = email, Email = email };
84 await _userManager.CreateAsync(user);
85 await _userManager.AddLoginAsync(user, info);
86 await _signInManager.SignInAsync(user, isPersistent: false);
87
88 return LocalRedirect(returnUrl ?? "/");
89}Your progress is saved in this browser, on this device only.