{"record":{"id":"30f508f75f8e53b3","repo":"fullstackhero/dotnet-starter-kit","slug":"two-factor-required-an-authenticator-code-is-required-to","errorCode":null,"errorMessage":"two_factor_required: An authenticator code is required to complete sign-in.","messagePattern":"two_factor_required: An authenticator code is required to complete sign-in\\.","errorType":"exception","errorClass":"CustomException","httpStatus":401,"severity":"error","filePath":"src/Modules/Identity/Modules.Identity/Services/IdentityService.cs","lineNumber":72,"sourceCode":"        var user = await FindAndValidateUserByCredentialsAsync(email, password);\n\n        ValidateUserStatus(user);\n        ValidateTenantStatus(tenant);\n\n        if (user.TwoFactorEnabled)\n        {\n            await VerifyTwoFactorOrThrowAsync(user, twoFactorCode);\n        }\n\n        var claims = await BuildUserClaimsAsync(user, tenant.Id, ct);\n        return (user.Id, claims);\n    }\n\n    private async Task VerifyTwoFactorOrThrowAsync(FshUser user, string? twoFactorCode)\n    {\n        if (string.IsNullOrWhiteSpace(twoFactorCode))\n        {\n            throw new CustomException(\n                \"two_factor_required: An authenticator code is required to complete sign-in.\",\n                errors: null,\n                HttpStatusCode.Unauthorized);\n        }\n\n        var valid = await _userManager.VerifyTwoFactorTokenAsync(\n            user,\n            _userManager.Options.Tokens.AuthenticatorTokenProvider,\n            twoFactorCode);\n\n        if (!valid)\n        {\n            _logger.LogWarning(\"Invalid two-factor code for user {UserId}\", user.Id);\n            throw new UnauthorizedException(\"two_factor_invalid: The authenticator code is invalid or expired.\");\n        }\n    }\n\n    public async Task<(string Subject, IEnumerable<Claim> Claims)?>","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/fullstackhero/dotnet-starter-kit/blob/3f2959e683e9f83f13e55e1678c9119f63c7e8e5/src/Modules/Identity/Modules.Identity/Services/IdentityService.cs#L54-L90","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Include the current 6-digit TOTP code from the authenticator app in the login request (twoFactorCode field).","Update the client login flow to a two-step login: submit credentials, then prompt for and send the authenticator code.","If 2FA should not be required, the user/admin can disable two-factor for the account via the identity endpoints.","Parse the two_factor_required marker in the 401 response to trigger the code-entry UI instead of showing a generic login failure."],"exampleFix":"// before\nconst res = await login({ email, password }); // 401 two_factor_required\n// after\nconst res = await login({ email, password, twoFactorCode: totpInput }); // succeeds","handlingStrategy":"try-catch","validationCode":"if (mfaRequired && !totpCode) {\n  showTwoFactorPrompt();\n  return; // don't call login without a code\n}","typeGuard":null,"tryCatchPattern":"try { await login({ email, password, twoFactorCode }); }\ncatch (e) {\n  if (e.message?.startsWith('two_factor_required')) { setStep('totp'); return; }\n  throw e;\n}","preventionTips":["Build the login flow with a dedicated 2FA step for accounts with MFA enabled.","Detect the two_factor_required marker to branch UI instead of failing.","Keep API scripts in sync when MFA is enforced on service accounts.","Consider app-specific recovery codes for automation."],"tags":["authentication","two-factor","identity","totp"],"backgroundTag":"missing-credentials","analyzedSha":"3f2959e683e9f83f13e55e1678c9119f63c7e8e5","analyzedAt":"2026-09-15T22:20:53.684Z","contentChangedAt":"2026-09-15T22:20:53.684Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}