Move passkey enrollment prompt to post-login dedicated page

After password login, users are routed through /Passkey/EnrollPrompt
before reaching the dashboard. The page shows an Enable / Maybe later
choice using the auth layout for a clean full-screen experience.
Users who already have a passkey are skipped past instantly.

Removes the floating bottom-right card from _Layout — the dedicated
page is a better UX touchpoint (one moment, right after login, rather
than a floating card on every page).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-25 16:41:01 -04:00
parent 92f71f62d0
commit edce8e8c4a
6 changed files with 144 additions and 84 deletions
@@ -255,6 +255,28 @@ public class PasskeyController : Controller
// ─── Management ───────────────────────────────────────────────────────────
// ─── Post-login enrollment prompt ─────────────────────────────────────────
/// <summary>
/// Shown immediately after password login. If the user already has a passkey,
/// redirects straight to returnUrl. Otherwise presents the "Enable Face ID" page.
/// </summary>
[Authorize]
[HttpGet("/Passkey/EnrollPrompt")]
public async Task<IActionResult> EnrollPrompt(string? returnUrl)
{
var user = await _userManager.GetUserAsync(User);
if (user == null) return Unauthorized();
// Skip prompt for users who already have at least one passkey
var hasPasskey = await _db.UserPasskeys.AnyAsync(p => p.UserId == user.Id);
if (hasPasskey)
return Redirect(returnUrl ?? "/");
ViewBag.ReturnUrl = returnUrl ?? "/";
return View();
}
/// <summary>Shows all passkeys registered by the current user.</summary>
[Authorize]
[HttpGet("/Passkey/Manage")]