{"record":{"id":"fd76a8393a8fbaa8","repo":"n8n-io/n8n","slug":"if-mfa-enabled-mfacode-is-required","errorCode":null,"errorMessage":"If MFA enabled, mfaCode is required.","messagePattern":"If MFA enabled, mfaCode is required\\.","errorType":"exception","errorClass":"BadRequestError","httpStatus":400,"severity":"error","filePath":"packages/cli/src/controllers/password-reset.controller.ts","lineNumber":209,"sourceCode":"\t/**\n\t * Verify password reset token and update password.\n\t */\n\t@Post('/change-password', {\n\t\tskipAuth: true,\n\t\tipRateLimit: true,\n\t})\n\tasync changePassword(\n\t\treq: AuthlessRequest,\n\t\tres: Response,\n\t\t@Body payload: ChangePasswordRequestDto,\n\t) {\n\t\tconst { token, password, mfaCode } = payload;\n\n\t\tconst user = await this.authService.resolvePasswordResetToken(token);\n\t\tif (!user) throw new NotFoundError('');\n\n\t\tif (user.mfaEnabled) {\n\t\t\tif (!mfaCode) throw new BadRequestError('If MFA enabled, mfaCode is required.');\n\n\t\t\tconst { decryptedSecret: secret } = await this.mfaService.getSecretAndRecoveryCodes(user.id);\n\n\t\t\tconst validToken = this.mfaService.totp.verifySecret({ secret, mfaCode });\n\n\t\t\tif (!validToken) throw new BadRequestError('Invalid MFA token.');\n\t\t}\n\n\t\tconst passwordHash = await this.passwordUtility.hash(password);\n\n\t\tawait this.userService.update(user.id, { password: passwordHash });\n\n\t\tthis.logger.info('User password updated successfully', { userId: user.id });\n\n\t\tthis.authService.issueCookie(res, user, user.mfaEnabled, req.browserId);\n\n\t\tthis.eventService.emit('user-updated', { user, fieldsChanged: ['password'] });\n","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/cli/src/controllers/password-reset.controller.ts#L191-L227","documentation":"The user resolving the reset has MFA enabled, so n8n requires the current TOTP code to authorize the password change. Submitting POST /change-password without an mfaCode for an mfaEnabled user is rejected with 400.","triggerScenarios":"POST /change-password for a user with user.mfaEnabled === true where the payload's mfaCode field is absent, empty, or undefined.","commonSituations":"The client form does not render an MFA prompt before submit; a direct API call omitted the field; the frontend assumed MFA was off for the account.","solutions":["Include a non-empty mfaCode in the request body alongside token and password.","Make the frontend prompt for the authenticator code whenever the user has MFA enabled (e.g. branch on a resolve-token response that indicates mfaEnabled).","Validate the payload shape before sending to avoid a round-trip."],"exampleFix":"// before\n// POST /change-password\n// { \"token\": \"...\", \"password\": \"newP@ss\" }\n// after\n// POST /change-password\n{\n  \"token\": \"...\",\n  \"password\": \"newP@ss\",\n  \"mfaCode\": \"123456\"\n}","handlingStrategy":"validation","validationCode":"// Validate payload shape before POST /change-password when the user has MFA.\nfunction isValidChangePasswordPayload(payload, userMfaEnabled) {\n  return Boolean(payload.token && payload.password) &&\n    (!userMfaEnabled || (typeof payload.mfaCode === 'string' && payload.mfaCode.trim() !== ''));\n}","typeGuard":"function hasRequiredMfaCode(payload, mfaEnabled) {\n  return !mfaEnabled || (typeof payload?.mfaCode === 'string' && payload.mfaCode.length > 0);\n}","tryCatchPattern":"try {\n  await api.post('/change-password', payload);\n} catch (e) {\n  if (e.status === 400 && /mfaCode is required/.test(e.message)) {\n    // prompt for the authenticator code and resend with mfaCode\n  } else { throw e; }\n}","preventionTips":["Branch the UI on the resolve-token response's mfaEnabled flag to render the MFA field.","Validate non-empty mfaCode client-side before submit."],"tags":["mfa","validation","auth","password-reset"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}