{"record":{"id":"e762d061ab937d7e","repo":"n8n-io/n8n","slug":"unauthorized-e762d0","errorCode":null,"errorMessage":"Unauthorized","messagePattern":"Unauthorized","errorType":"exception","errorClass":"AuthError","httpStatus":401,"severity":"error","filePath":"packages/cli/src/auth/auth.service.ts","lineNumber":133,"sourceCode":"\t\t\t// :projectId in req.baseUrl, so this one needs a pattern.\n\t\t\tnew RegExp(\n\t\t\t\t`^/${escapeRegExp(restEndpoint)}/projects/[^/]+/agents/v2/:agentId/chat/attachments/:attachmentId$`,\n\t\t\t),\n\t\t];\n\t}\n\n\tcreateAuthMiddleware({\n\t\tallowSkipMFA,\n\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,","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/cli/src/auth/auth.service.ts#L115-L151","documentation":"Raised by the auth middleware when the presented auth cookie token is found in the invalid-auth-token repository — i.e. the token has been revoked or the user logged out. The token is checked via existsBy({ token }) before JWT verification. The resulting AuthError is caught and triggers cookie clearing and a 401 response. Distinct from an invalid/unsigned JWT (JsonWebTokenError).","triggerScenarios":"A request carries an auth cookie that was invalidated by logout, password change, admin session revocation, or token rotation. Also after a server restart where invalid tokens are persisted. The user's browser still holds the old cookie.","commonSituations":"User logged out in another tab but the current tab still sends the old cookie; SSO/session cleanup revoked tokens; concurrent sessions after a password change; stale cookies after an instance restore.","solutions":["On the client, handle the 401 by clearing the auth cookie and redirecting to login.","Ensure logout invalidates the token server-side (it does) and the client drops the cookie.","If occurring app-wide after a restart/restore, have all clients re-authenticate."],"exampleFix":"// client-side fetch wrapper\n// before\nconst res = await fetch('/api/workflows');\n\n// after\nconst res = await fetch('/api/workflows');\nif (res.status === 401) {\n  document.cookie = AUTH_COOKIE_NAME + '=; Max-Age=0; path=/';\n  window.location.href = '/signin';\n}","handlingStrategy":"try-catch","validationCode":"// Client: before each request, the cookie is present; nothing to pre-validate.\n// Server: the check is authoritative. To reduce surface, clear cookies on logout.\nawait authService.invalidateToken(req); // adds token to invalid-auth-token repo","typeGuard":"import { AuthError } from 'n8n-workflow';\nfunction isAuthError(e: unknown): e is AuthError {\n  return e instanceof AuthError;\n}","tryCatchPattern":"// Express error handler\nif (err instanceof AuthError && err.message === 'Unauthorized') {\n  res.clearCookie(AUTH_COOKIE_NAME);\n  return res.status(401).json({ status: 'error', message: 'Unauthorized' });\n}","preventionTips":["On the client, treat any 401 by clearing the auth cookie and redirecting to login.","Ensure logout calls the server-side invalidate endpoint so the token is revoked.","Rotate tokens on password change / admin revocation to invalidate stale sessions."],"tags":["auth","authentication","session","unauthorized"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}