{"record":{"id":"0764048087a2fa67","repo":"n8n-io/n8n","slug":"mfa-not-used-during-authentication","errorCode":null,"errorMessage":"MFA not used during authentication","messagePattern":"MFA not used during authentication","errorType":"exception","errorClass":"AuthError","httpStatus":401,"severity":"error","filePath":"packages/cli/src/auth/auth.service.ts","lineNumber":142,"sourceCode":"\t\tallowSkipPreviewAuth,\n\t\tallowUnauthenticated,\n\t}: CreateAuthMiddlewareOptions) {\n\t\treturn async (req: AuthenticatedRequest, res: Response, next: NextFunction) => {\n\t\t\tconst token = req.cookies[AUTH_COOKIE_NAME];\n\n\t\t\tif (token) {\n\t\t\t\ttry {\n\t\t\t\t\tconst isInvalid = await this.invalidAuthTokenRepository.existsBy({ token });\n\t\t\t\t\tif (isInvalid) throw new AuthError('Unauthorized');\n\n\t\t\t\t\tconst [user, { usedMfa }] = await this.resolveJwt(token, req, res);\n\t\t\t\t\tconst mfaEnforced = await this.mfaService.isMFAEnforced();\n\n\t\t\t\t\tif (mfaEnforced && !usedMfa && !allowSkipMFA) {\n\t\t\t\t\t\t// If MFA is enforced, we need to check if the user has MFA enabled and used it during authentication\n\t\t\t\t\t\tif (user.mfaEnabled) {\n\t\t\t\t\t\t\t// If the user has MFA enforced, but did not use it during authentication, we need to throw an error\n\t\t\t\t\t\t\tthrow new AuthError('MFA not used during authentication');\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// User doesn't have MFA enabled, but MFA is enforced\n\t\t\t\t\t\t\t// They need to set up MFA before accessing most endpoints\n\t\t\t\t\t\t\tif (allowUnauthenticated) {\n\t\t\t\t\t\t\t\t// Don't set req.user to avoid giving full access to semi-authenticated users\n\t\t\t\t\t\t\t\t// Instead, set a flag in authInfo to indicate MFA enrollment is required\n\t\t\t\t\t\t\t\t// This allows endpoints to handle this state appropriately (e.g., return public settings)\n\t\t\t\t\t\t\t\treq.authInfo = {\n\t\t\t\t\t\t\t\t\tusedMfa,\n\t\t\t\t\t\t\t\t\tmfaEnrollmentRequired: true,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\treturn next();\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// In this case we don't want to clear the cookie, to allow for MFA setup\n\t\t\t\t\t\t\tres.status(401).json({ status: 'error', message: 'Unauthorized', mfaRequired: true });\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/cli/src/auth/auth.service.ts#L124-L160","documentation":"MFA is enforced for the deployment, the user has MFA enabled, but the request's auth cookie was issued without completing an MFA step (usedMfa === false). The middleware refuses to grant full access and throws AuthError, which is caught and results in cookie clearing + 401. The user must re-authenticate including the MFA step. This is distinct from the mfaEnrollmentRequired branch where the user has not yet set up MFA.","triggerScenarios":"A user logs in with username/password but does not complete the MFA challenge, then attempts to access a protected endpoint; an admin enables MFA enforcement after the user obtained a non-MFA session; the MFA challenge was skipped or failed silently and the session cookie lacks the usedMfa flag.","commonSituations":"Admin turns on MFA enforcement while users have active non-MFA sessions; a login flow bug that issues the auth cookie before MFA completion; client that bypasses the MFA step; clock/token state that drops the usedMfa claim.","solutions":["Have the user log out and back in, completing the MFA challenge so the new cookie carries usedMfa = true.","If using a custom login client, ensure the MFA verification step runs before accepting the session cookie.","Verify the JWT includes the MFA-used claim after a successful MFA login; if not, check the login service."],"exampleFix":"// login flow (client)\n// before: accept session after password only\nconst { token } = await login(user, pass);\nsetCookie(token); // cookie lacks usedMfa -> 1279 on next request\n\n// after: complete MFA then accept\nconst { mfaTicket } = await login(user, pass);\nconst { token } = await verifyMfa(mfaTicket, code);\nsetCookie(token);","handlingStrategy":"try-catch","validationCode":"// Client: ensure MFA step completes before persisting the session cookie\nconst { mfaTicket } = await login(user, pass);\nif (mfaTicket) {\n  const { token } = await verifyMfa(mfaTicket, code);\n  setCookie(token);\n} else {\n  setCookie(passwordToken); // only when MFA is not enforced\n}","typeGuard":"import { AuthError } from 'n8n-workflow';\nfunction isMfaRequiredError(e: unknown): boolean {\n  return e instanceof AuthError && /MFA not used/i.test(e.message);\n}","tryCatchPattern":"// Express middleware\ntry {\n  await next();\n} catch (err) {\n  if (err instanceof AuthError && /MFA not used/i.test(err.message)) {\n    res.clearCookie(AUTH_COOKIE_NAME);\n    return res.status(401).json({ status: 'error', message: 'MFA required', mfaRequired: true });\n  }\n  throw err;\n}","preventionTips":["Complete the MFA challenge before accepting a session cookie so it carries usedMfa = true.","When enabling MFA enforcement, force all existing sessions to re-authenticate.","Verify the JWT includes the MFA-used claim after a successful MFA login."],"tags":["auth","mfa","authentication","security"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}