Help us improve
Share bugs, ideas, or general feedback.
From dotnet-skills
Production-grade patterns for ASP.NET Core Identity in Razor Pages and web apps. Covers setup, customization, security hardening, auth flows, roles/claims, external providers, and integration best practices for .NET 8+ / .NET 9+. Use when implementing authentication and authorization in ASP.NET Core applications, configuring ASP.NET Core Identity, setting up external login providers, or managing roles and claims.
npx claudepluginhub wshaddix/dotnet-skillsHow this skill is triggered — by the user, by Claude, or both
Slash command
/dotnet-skills:asp-net-core-identity-patternsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are a senior .NET security & identity architect. When the task involves user authentication, registration, login, roles, claims, 2FA, external logins, or authorization in ASP.NET Core (especially Razor Pages), strictly follow these patterns. Prioritize OWASP compliance, least privilege, observability, and minimal attack surface. Target .NET 8+ with nullable enabled.
Guides ASP.NET Core authentication and authorization with JWT bearer tokens, OpenID Connect, ASP.NET Identity, policies, roles, claims, and API keys. For login, endpoint protection, and auth rules.
Implementing API auth. Identity, OAuth/OIDC, JWT bearer, passkeys (WebAuthn), CORS, rate limiting.
Adds login, logout, and user profile to ASP.NET Core MVC, Razor Pages, or Blazor Server apps using Auth0.AspNetCore.Authentication with cookie-based authentication.
Share bugs, ideas, or general feedback.
You are a senior .NET security & identity architect. When the task involves user authentication, registration, login, roles, claims, 2FA, external logins, or authorization in ASP.NET Core (especially Razor Pages), strictly follow these patterns. Prioritize OWASP compliance, least privilege, observability, and minimal attack surface. Target .NET 8+ with nullable enabled.
ASP.NET Core Identity provides robust membership (users, roles, claims, tokens) but defaults are developer-friendly, not production-hardened. Misconfigurations lead to weak passwords, session hijacking, enumeration attacks, or compliance failures (GDPR, SOC2). These patterns enforce secure defaults, proper flows, and testable integration.
AddDefaultIdentity<IdentityUser>() or AddIdentity<IdentityUser, IdentityRole>() for role support.AddEntityFrameworkStores<ApplicationDbContext>().builder.Services.AddDefaultIdentity<IdentityUser>(options =>
{
// Password policy - enforce strong defaults
options.Password.RequiredLength = 12;
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireUppercase = true;
options.Password.RequireNonAlphanumeric = true;
options.Password.RequiredUniqueChars = 6;
// Lockout - prevent brute force
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(15);
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.AllowedForNewUsers = true;
// Sign-in requirements
options.SignIn.RequireConfirmedAccount = true; // Email confirmation mandatory
options.SignIn.RequireConfirmedEmail = true;
options.SignIn.RequireConfirmedPhoneNumber = false; // Optional 2FA/SMS
// User settings
options.User.RequireUniqueEmail = true;
options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders(); // For password reset, email confirmation, 2FA
UseRouting():app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();
app.UseHsts();
app.UseHttpsRedirection();
dotnet aspnet-codegenerator identity -dc ApplicationDbContext \
--files "Account.Register;Account.Login;Account.Logout;Account.ForgotPassword;Account.ConfirmEmail;Account.Manage.Index;Account.Manage.ChangePassword;Account.Manage.TwoFactorAuthentication"
private readonly UserManager<IdentityUser> _userManager;
private readonly SignInManager<IdentityUser> _signInManager;
private readonly ILogger<RegisterModel> _logger;
public RegisterModel(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager,
ILogger<RegisterModel> logger)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
}
@Html.AntiForgeryToken() and [ValidateAntiForgeryToken] on POST handlers.[Authorize] on protected PageModels:[Authorize(Policy = "RequireAdminRole")]
public class AdminModel : PageModel { ... }
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("RequireAdminRole", policy =>
policy.RequireRole("Admin"));
options.AddPolicy("CanEditContent", policy =>
policy.RequireClaim("Permission", "EditContent")
.RequireAuthenticatedUser());
});
[Authorize(Policy = "CanEditContent")] or in RequireAuthorization() on endpoints.builder.Services.ConfigureApplicationCookie(options =>
{
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always; // HTTPS only
options.Cookie.SameSite = SameSiteMode.Strict; // Mitigate CSRF
options.ExpireTimeSpan = TimeSpan.FromDays(14);
options.SlidingExpiration = true;
options.LoginPath = "/Identity/Account/Login";
options.AccessDeniedPath = "/Identity/Account/AccessDenied";
});
TwoFactorAuthentication page.AspNetCoreRateLimit or middleware).Microsoft.AspNetCore.Identity meters (new in .NET 10+) for anomaly detection.builder.Services.AddAuthentication()
.AddGoogle(options =>
{
options.ClientId = builder.Configuration["Authentication:Google:ClientId"];
options.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"];
});
SignInManager.GetExternalAuthenticationSchemesAsync().IdentityUser sparingly (add properties like FirstName, LastName):public class ApplicationUser : IdentityUser
{
public string FullName { get; set; } = string.Empty;
}
SignInManager or custom claims factory.UserManager / SignInManager mocks (Moq).WebApplicationFactory.public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid) return Page();
var user = CreateUser(); // Factory method
await _userStore.SetUserNameAsync(user, Input.Email, CancellationToken.None);
await _emailStore.SetEmailAsync(user, Input.Email, CancellationToken.None);
var result = await _userManager.CreateAsync(user, Input.Password);
if (result.Succeeded)
{
_logger.LogInformation("User created a new account with password.");
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
// Send email with confirmation link...
if (_userManager.Options.SignIn.RequireConfirmedAccount)
return RedirectToPage("RegisterConfirmation", new { email = Input.Email });
await _signInManager.SignInAsync(user, isPersistent: false);
return LocalRedirect(returnUrl);
}
foreach (var error in result.Errors) ModelState.AddModelError(string.Empty, error.Description);
return Page();
}
[Authorize(Roles = "Admin")] everywhere → Prefer claims/policies.Apply this skill when auth/identity tasks appear. Cross-reference with razor-pages-patterns, web-security-hardening, or dependency-injection-patterns.