fullstackhero/dotnet-starter-kit · error · CustomException

two_factor_required: An authenticator code is required to…

Error message

two_factor_required: An authenticator code is required to complete sign-in.

What it means

When a user has two-factor authentication enabled, IdentityService.ValidateCredentialsAsync calls VerifyTwoFactorOrThrowAsync; if no authenticator (TOTP) code is supplied alongside the credentials it throws CustomException with 401 and the two_factor_required marker. Login is intentionally incomplete until the second factor is provided.

Solutions

  1. Include the current 6-digit TOTP code from the authenticator app in the login request (twoFactorCode field).
  2. Update the client login flow to a two-step login: submit credentials, then prompt for and send the authenticator code.
  3. If 2FA should not be required, the user/admin can disable two-factor for the account via the identity endpoints.
  4. Parse the two_factor_required marker in the 401 response to trigger the code-entry UI instead of showing a generic login failure.

Example fix

// before
const res = await login({ email, password }); // 401 two_factor_required
// after
const res = await login({ email, password, twoFactorCode: totpInput }); // succeeds
Defensive patterns

Strategy: try-catch

Validate before calling

if (mfaRequired && !totpCode) {
  showTwoFactorPrompt();
  return; // don't call login without a code
}

Try / catch

try { await login({ email, password, twoFactorCode }); }
catch (e) {
  if (e.message?.startsWith('two_factor_required')) { setStep('totp'); return; }
  throw e;
}

Prevention

When it happens

Trigger: Signing in with correct username/password for a 2FA-enabled account while omitting the twoFactorCode parameter; clients using a legacy login endpoint or DTO that has no code field; MFA enabled server-side after the client login flow was built.

Common situations: User enables authenticator app, old mobile/SPA client stops working; automated scripts doing password-only login; frontend login form lacking the TOTP step; API consumers not aware MFA was enforced.

Understand the failure class

Related errors


AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15). Data as JSON: /api/errors/30f508f75f8e53b3. Report an issue: GitHub.

Appendix: source

Thrown at src/Modules/Identity/Modules.Identity/Services/IdentityService.cs:72

        var user = await FindAndValidateUserByCredentialsAsync(email, password);

        ValidateUserStatus(user);
        ValidateTenantStatus(tenant);

        if (user.TwoFactorEnabled)
        {
            await VerifyTwoFactorOrThrowAsync(user, twoFactorCode);
        }

        var claims = await BuildUserClaimsAsync(user, tenant.Id, ct);
        return (user.Id, claims);
    }

    private async Task VerifyTwoFactorOrThrowAsync(FshUser user, string? twoFactorCode)
    {
        if (string.IsNullOrWhiteSpace(twoFactorCode))
        {
            throw new CustomException(
                "two_factor_required: An authenticator code is required to complete sign-in.",
                errors: null,
                HttpStatusCode.Unauthorized);
        }

        var valid = await _userManager.VerifyTwoFactorTokenAsync(
            user,
            _userManager.Options.Tokens.AuthenticatorTokenProvider,
            twoFactorCode);

        if (!valid)
        {
            _logger.LogWarning("Invalid two-factor code for user {UserId}", user.Id);
            throw new UnauthorizedException("two_factor_invalid: The authenticator code is invalid or expired.");
        }
    }

    public async Task<(string Subject, IEnumerable<Claim> Claims)?>

View on GitHub (pinned to 3f2959e683)