Skip to main content

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:

PageRoutePurpose
Sign In/auth/sign-inLogin with username/password or external provider
Sign Out/auth/sign-outLogout and clear session
Request Password Reset/auth/request-password-resetInitiate password recovery
Reset Password/auth/reset-passwordEnter new password with token
Set Password/auth/set-passwordSet initial password (first-time users)
Request Account Verification/auth/request-account-verificationResend email verification link
Account Verification/auth/account-verificationConfirm email address
Validate Email MFA/auth/validate-email-mfaEnter email one-time code
Validate SMS MFA/auth/validate-sms-mfaEnter SMS one-time code
Validate App MFA/auth/validate-app-mfaEnter TOTP from authenticator app
Validate Device MFA/auth/validate-device-mfaBiometric/hardware key validation
Authentication Failed/auth/authentication-failedError page for failed attempts
User Create Unavailable/auth/user-create-unavailableWhen registration is disabled

Registration Area (/registration/*)

User registration and email confirmation:

PageRoutePurpose
Sign Up/registration/sign-upCreate new user account
Confirm Email/registration/confirm-emailVerify email address after signup
Post Sign Up/registration/post-sign-upThank you / redirect page

First Run Area (/first-run/*)

Initial system setup (when no users exist):

PageRoutePurpose
Initial User Setup/first-run/initial-user-setupCreate first admin user on fresh install
Setup Completed/first-run/setup-completedConfirmation 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

The easiest approach. Create pages in your application with the same routes and they will take precedence over the RCL versions.

Steps:

  1. Create the directory structure in your host project:

    Areas/
    ├── Auth/
    │ └── Pages/
    │ └── UserAuthentication.cshtml (your custom version)
    ├── Registration/
    │ └── Pages/
    │ └── SignUp.cshtml
    └── FirstRun/
    └── Pages/
    └── InitialUserSetup.cshtml
  2. 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
    }
  3. 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:

  1. Override the shared layout:

    Areas/Auth/Pages/Shared/_Layout.cshtml
  2. 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;
    }
  3. Reference in layout:

    <link rel="stylesheet" href="/auth-custom.css" />

Option 3: Extract & Customize Manually

For complete control, extract the entire RCL:

  1. Copy all files from PearDrop.Auth.RazorPages into your project
  2. Remove the NuGet dependency
  3. Modify pages, styles, logic as needed
  4. Serve your custom auth UI

Trade-off: You lose automatic updates from NuGet.


Common Customizations

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

  1. Keep it simple - Don't overcomplicate the auth flow
  2. Brand consistently - Use your company colors, logo, fonts
  3. Test MFA flows - Especially email/SMS verification
  4. Handle errors gracefully - Clear messages for invalid credentials, expired tokens
  5. Consider accessibility - Ensure pages work with screen readers
  6. Mobile-friendly - Test on phones and tablets
  7. Maintain security - Never remove CSRF protection or validation
  8. 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/ and obj/ directories
  • Rebuild the solution
  • Verify the file path matches exactly (case-sensitive on Linux)
  • Check that .csproj includes 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 wwwroot is 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