Skip to content
Introducing the next era of Duende IdentityServer. Read our CEO’s announcement

Multi-Factor Authentication

Multi-factor authentication (MFA) requires users to prove their identity with more than one factor: typically something they know (a password) combined with something they have (a device or security key) or something they are (a biometric). IdentityServer handles the protocol layer (OpenID Connect, OAuth 2.0, SAML) and delegates the actual authentication experience, including MFA, to the hosting application’s login UI.

Duende User Management provides production-ready MFA building blocks that integrate directly with IdentityServer. The library handles the cryptographic operations, credential storage, verification logic, and rate limiting. You provide the UI.

Supported second factors:

MethodDescriptionUse Case
TOTPTime-based codes from authenticator apps (Microsoft Authenticator, Google Authenticator, etc.)Most common MFA for enterprise apps
PasskeysWebAuthn/FIDO2 phishing-resistant authentication via biometrics or hardware keysHighest security; can also serve as primary auth
OTPOne-time codes delivered via email or SMSStep-up authentication or passwordless primary
Recovery CodesSingle-use backup codesFallback when the primary 2FA method is unavailable

A typical MFA flow with User Management:

  1. User authenticates with a primary factor (password, OTP, or external provider)
  2. Application checks whether the user has a second factor enrolled
  3. User completes the second-factor challenge (TOTP code, passkey ceremony, etc.)
  4. Application establishes the IdentityServer session with an amr claim reflecting MFA being used
Login.cshtml.cs
public class LoginModel(
IUserAuthenticatorsSelfService authenticatorsSelfService)
: PageModel
{
public async Task<IActionResult> AfterPrimaryAuthSucces(UserSubjectId userId, CancellationToken ct)
{
var authenticators = await authenticatorsSelfService.TryGetAsync(userId, ct);
if (authenticators?.TotpDeviceNames.Count > 0)
{
// Redirect to TOTP verification page
return RedirectToPage("/LoginWith2FA");
}
if (authenticators?.Passkeys.Count > 0)
{
// Redirect to passkey verification page
return RedirectToPage("/LoginWithPasskey");
}
return RedirectToPage("/LoginWithRecoveryCode");
}
}

For detailed implementation guides, see:

If you are using ASP.NET Core Identity as your user store, it provides its own MFA support including TOTP with authenticator apps. Microsoft’s general MFA guidelines cover configuration options for ASP.NET Core.

When using IdentityServer as a federation gateway, interactive users authenticate at the upstream identity provider. The upstream provider handles the entire authentication process, including any MFA it requires. No special configuration is needed in IdentityServer for this scenario.

Clients can signal that MFA is required using the acr_values parameter in the authorization request. Your login UI can read this from the authorization context and enforce a second-factor challenge accordingly:

var context = await interaction.GetAuthorizationContextAsync(returnUrl, HttpContext.RequestAborted);
if (context?.AcrValues.Contains("mfa") == true)
{
// Enforce second-factor authentication regardless of user preference
}