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-skillsThis skill uses the workspace's default tool permissions.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Implements structured self-debugging workflow for AI agent failures: capture errors, diagnose patterns like loops or context overflow, apply contained recoveries, and generate introspection reports.
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.