Skip to content

feat: Add MFA challenge UI pages for passkey-as-second-factor flow #57

@devondragon

Description

@devondragon

Summary

Implement MFA challenge UI pages in the demo app to demonstrate the library's new MFA wrapper (see devondragon/SpringUserFramework#268).

When a consuming app enables MFA via:

user.mfa.enabled: true
user.mfa.factors: PASSWORD, WEBAUTHN

...Spring Security requires both factors for all authenticated endpoints. After a user logs in with their password, they need a passkey challenge page to complete the second factor. This issue covers building that page and the surrounding UX in the demo app.

What's Needed

1. WebAuthn MFA Challenge Page

A page (e.g., /user/mfa/webauthn-challenge.html) that:

  • Calls GET /user/mfa/status API to check which factors are satisfied/missing
  • If WEBAUTHN factor is missing, triggers the WebAuthn assertion ceremony (browser biometric/passkey prompt)
  • On success, redirects to the originally requested URL
  • Handles errors (no passkey registered, user cancelled, timeout)

2. Login Page Updates

The existing login page may need updates to:

  • Detect when MFA is enabled (via /user/mfa/status or a server-side flag)
  • Show appropriate messaging after password login ("Please complete passkey verification...")
  • Handle the redirect flow: password login → MFA challenge → original destination

3. Demo App Configuration

Example application.yml configuration showing MFA enabled:

user:
  webauthn:
    enabled: true
    rpId: localhost
    rpName: Demo App
    allowedOrigins: https://localhost:8443
  mfa:
    enabled: true
    factors: PASSWORD, WEBAUTHN
    webauthn-entry-point-uri: /user/mfa/webauthn-challenge.html

4. Testing Scenarios

  • Password login → passkey challenge → access granted
  • Password login → cancel passkey → access denied (stays on challenge page)
  • Direct passkey login (should this satisfy both factors? Depends on config)
  • User without passkey registered → helpful error message
  • MFA disabled → normal login flow unchanged

Dependencies

Notes

  • The demo app is the reference implementation for consuming app developers
  • Focus on clean, understandable code that serves as an example
  • WebAuthn JavaScript API calls follow the same pattern as the existing passkey registration/login code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions