Authentication UI & Customization
PearDrop includes a pre-built authentication UI via the PearDrop.Auth.RazorPages NuGet package. This Razor Class Library (RCL) provides production-ready pages for login, registration, password reset, MFA, and more.
What's Included
Auth Area (/auth/*)
The core authentication pages:
| Page | Route | Purpose |
|---|---|---|
| Sign In | /auth/sign-in | Login with username/password or external provider |
| Sign Out | /auth/sign-out | Logout and clear session |
| Request Password Reset | /auth/request-password-reset | Initiate password recovery |
| Reset Password | /auth/reset-password | Enter new password with token |
| Set Password | /auth/set-password | Set initial password (first-time users) |
| Request Account Verification | /auth/request-account-verification | Resend email verification link |
| Account Verification | /auth/account-verification | Confirm email address |
| Validate Email MFA | /auth/validate-email-mfa | Enter email one-time code |
| Validate SMS MFA | /auth/validate-sms-mfa | Enter SMS one-time code |
| Validate App MFA | /auth/validate-app-mfa | Enter TOTP from authenticator app |
| Validate Device MFA | /auth/validate-device-mfa | Biometric/hardware key validation |
| Authentication Failed | /auth/authentication-failed | Error page for failed attempts |
| User Create Unavailable | /auth/user-create-unavailable | When registration is disabled |
Registration Area (/registration/*)
User registration and email confirmation:
| Page | Route | Purpose |
|---|---|---|
| Sign Up | /registration/sign-up | Create new user account |
| Confirm Email | /registration/confirm-email | Verify email address after signup |
| Post Sign Up | /registration/post-sign-up | Thank you / redirect page |
First Run Area (/first-run/*)
Initial system setup (when no users exist):
| Page | Route | Purpose |
|---|---|---|
| Initial User Setup | /first-run/initial-user-setup | Create first admin user on fresh install |
| Setup Completed | /first-run/setup-completed | Confirmation after initial setup |
View Components
Reusable components shared across pages:
- PasswordRequirementsViewComponent - Display password policy requirements
Page Features
All auth pages include:
- Responsive Bootstrap UI - Works on desktop, tablet, mobile
- ASP.NET Core validation - Server-side and client-side errors
- Security features - Anti-forgery tokens, CSRF protection
- Customizable branding - Logo/image placeholders
- Multi-language ready - Localization support via standard .NET cultures
- Accessible forms - ARIA labels, proper heading hierarchy
- Error messaging - User-friendly feedback for validation and business logic errors
Customizing the UI
Option 1: Override Pages in Host Project (Recommended)
The easiest approach. Create pages in your application with the same routes and they will take precedence over the RCL versions.
Steps:
-
Create the directory structure in your host project:
Areas/
├── Auth/
│ └── Pages/
│ └── UserAuthentication.cshtml (your custom version)
├── Registration/
│ └── Pages/
│ └── SignUp.cshtml
└── FirstRun/
└── Pages/
└── InitialUserSetup.cshtml -
Optional: Copy the code-behind (.cshtml.cs) only if you need custom logic.
For UI-only changes, you can override just the .cshtml file and the RCL's code-behind will handle the logic:
<!-- Areas/Auth/Pages/UserAuthentication.cshtml -->
<!-- Just modify the HTML and styling, leave logic to RCL -->If you need custom logic, copy and modify the code-behind:
// Areas/Auth/Pages/UserAuthentication.cshtml.cs
public class UserAuthentication : PageModel
{
private readonly ICommandRunner commandRunner;
private readonly IQueryRunner queryRunner;
public UserAuthentication(
ICommandRunner commandRunner,
IQueryRunner queryRunner)
{
this.commandRunner = commandRunner;
this.queryRunner = queryRunner;
}
// Your custom logic here
} -
Update the layout/styling to match your brand:
<!-- Areas/Auth/Pages/UserAuthentication.cshtml -->
@{
ViewData["Title"] = "My Custom Login Title";
}
<section class="my-custom-login-style">
<!-- Your custom HTML here -->
</section>
Option 2: Modify Layout & Styling Only
If you want to keep the page logic but customize appearance:
-
Override the shared layout:
Areas/Auth/Pages/Shared/_Layout.cshtml -
Update CSS via wwwroot:
/* wwwroot/auth-custom.css */
#auth-container {
background: linear-gradient(to right, #667eea 0%, #764ba2 100%);
}
.form-control {
border-radius: 8px;
border: 2px solid #667eea;
} -
Reference in layout:
<link rel="stylesheet" href="/auth-custom.css" />
Option 3: Extract & Customize Manually
For complete control, extract the entire RCL:
- Copy all files from
PearDrop.Auth.RazorPagesinto your project - Remove the NuGet dependency
- Modify pages, styles, logic as needed
- Serve your custom auth UI
Trade-off: You lose automatic updates from NuGet.
Common Customizations
Change Logo
Replace the placeholder image:
<!-- Areas/Auth/Pages/UserAuthentication.cshtml -->
<img src="~/images/my-logo.png" alt="My Company Logo" class="logo-large" />
Customize Form Fields
Add custom fields to signup or modify validation:
// Areas/Registration/Pages/SignUp.cshtml.cs
[BindProperty]
public string Company { get; set; }
[BindProperty]
public string Department { get; set; }
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
var command = new CreateUserCommand(
Username: Input.Username,
Email: Input.Email,
Password: Input.Password);
var result = await this.commandRunner.ExecuteAsync(command);
// ... rest of logic
}
Add Company Branding
Update the layout and styling to match your brand:
<!-- Areas/Shared/_Layout.cshtml -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>My App | @ViewData["Title"]</title>
<link rel="stylesheet" href="~/css/company-theme.css" />
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="/">
<img src="~/images/company-logo.svg" alt="My Company" height="40" />
</a>
</div>
</nav>
@RenderBody()
</body>
</html>
Customize Error Messages
Override error display and messages:
<!-- Areas/Auth/Pages/UserAuthentication.cshtml -->
@if (Model.InError)
{
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<strong>Sign In Failed</strong>
<p>@Model.ErrorFeedback</p>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
}
Structure of RazorPages Package
The PearDrop.Auth.RazorPages NuGet package is a Razor Class Library (RCL) containing:
PearDrop.Auth.RazorPages/
├── Areas/
│ ├── Auth/
│ │ ├── Pages/
│ │ │ ├── UserAuthentication.cshtml (.cs)
│ │ │ ├── PasswordReset.cshtml (.cs)
│ │ │ ├── ValidateEmailMfaCode.cshtml (.cs)
│ │ │ └── ... (other auth pages)
│ │ └── Shared/
│ │ ├── _Layout.cshtml
│ │ ├── _ViewStart.cshtml
│ │ └── _ViewImports.cshtml
│ ├── Registration/
│ │ ├── Pages/
│ │ │ ├── SignUp.cshtml (.cs)
│ │ │ └── ... (registration pages)
│ │ └── Shared/
│ └── FirstRun/
│ ├── Pages/
│ │ └── ... (setup pages)
│ └── Shared/
├── ViewComponents/
│ └── PasswordRequirementsViewComponent.cs
├── wwwroot/
│ ├── css/
│ ├── js/
│ └── images/
└── Assets/
└── ... (static content)
Key: When your host project has pages in Areas/Auth/Pages/UserAuthentication.cshtml, ASP.NET Core prioritizes it over the RCL version.
Best Practices
- Keep it simple - Don't overcomplicate the auth flow
- Brand consistently - Use your company colors, logo, fonts
- Test MFA flows - Especially email/SMS verification
- Handle errors gracefully - Clear messages for invalid credentials, expired tokens
- Consider accessibility - Ensure pages work with screen readers
- Mobile-friendly - Test on phones and tablets
- Maintain security - Never remove CSRF protection or validation
- Use layouts - Share common styling across all auth pages
Troubleshooting
Custom Pages Not Loading
Problem: You created Areas/Auth/Pages/UserAuthentication.cshtml but the RCL version still loads.
Solution:
- Clear
bin/andobj/directories - Rebuild the solution
- Verify the file path matches exactly (case-sensitive on Linux)
- Check that
.csprojincludes Razor files:<EnableDefaultRazorGenerateItems>true</EnableDefaultRazorGenerateItems>
Styles Not Applying
Problem: Custom CSS file not applied to auth pages.
Solution:
- Verify CSS file path is correct in the HTML
- Check that
wwwrootis served properly - Use browser DevTools to confirm CSS is loaded
- Clear browser cache or use incognito mode
Custom Validation Not Working
Problem: Custom fields added to signup page don't validate.
Solution:
- Add
[BindProperty]to your properties - Add
[Required],[StringLength], etc. attributes - Validate in
OnPostAsync()before executing the command - Return
Page()if validation fails