{"record":{"id":"6ff21c157a888350","repo":"immich-app/immich","slug":"failed-login-attempt-for-user-dto-email-from-ip-address","errorCode":null,"errorMessage":"Failed login attempt for user ${dto.email} from ip address ${details.clientIp}","messagePattern":"Failed login attempt for user (.+?) from ip address (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"server/src/services/auth.service.ts","lineNumber":72,"sourceCode":"    uri: string;\n  };\n};\n\n@Injectable()\nexport class AuthService extends BaseService {\n  async login(dto: LoginCredentialDto, details: LoginDetails) {\n    const config = await this.getConfig({ withCache: false });\n    if (!config.passwordLogin.enabled) {\n      throw new UnauthorizedException('Password login has been disabled');\n    }\n\n    const user = await this.userRepository.getByEmail(dto.email, { withPassword: true });\n    // Always run bcrypt so response time is constant regardless of whether the email\n    // is registered, preventing timing-based user enumeration.\n    const isAuthenticated = this.cryptoRepository.compareBcrypt(dto.password, user?.password ?? LOGIN_DUMMY_HASH);\n\n    if (!user || !user.password || !isAuthenticated) {\n      this.logger.warn(`Failed login attempt for user ${dto.email} from ip address ${details.clientIp}`);\n      throw new UnauthorizedException('Incorrect email or password');\n    }\n\n    return this.createLoginResponse(user, details);\n  }\n\n  async logout(auth: AuthDto, authType: AuthType): Promise<LogoutResponseDto> {\n    let oauthBearerToken: string | undefined;\n    if (auth.session) {\n      const session = await this.sessionRepository.get(auth.session.id);\n      oauthBearerToken = session?.oauthBearerToken ?? undefined;\n      await this.sessionRepository.delete(auth.session.id);\n      await this.eventRepository.emit('SessionDelete', { sessionId: auth.session.id });\n    }\n\n    return {\n      successful: true,\n      redirectUri: await this.getLogoutEndpoint(authType, oauthBearerToken),","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/immich-app/immich/blob/f48d4b332127ad365ba256108799ca8f571d2dd5/server/src/services/auth.service.ts#L54-L90","documentation":"On login, the service looks up the user by email and compares the bcrypt password (against a dummy hash when the user does not exist, to keep timing constant). If any check fails, this warning is logged with the attempted email and client IP and an UnauthorizedException('Incorrect email or password') is thrown to the client.","triggerScenarios":"POST /auth/login with credentials where the email is unknown, the user has no password set (OAuth-only account), or the bcrypt comparison fails.","commonSituations":"Typo in email or password; user created via OAuth never set a server password; Caps Lock/keyboard layout issues; brute-force probing (watch the IP in logs); after password change with a cached client.","solutions":["Confirm the email exists and the password is correct; reset via 'Forgot password' if needed.","If the account is OAuth-only, log in via OAuth or set a password through admin settings.","Repeated attempts from one IP: check rate-limiting / consider blocking the address.","If the password is definitely correct, re-hash/reset the password in admin user settings."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (!email.includes('@') || password.length === 0) {\n  throw new BadRequestException('Email and password are required');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await api.login({ email, password });\n} catch (e) {\n  if (e instanceof UnauthorizedException) {\n    showToast('Incorrect email or password');\n  } else throw e;\n}","preventionTips":["Set a server password for OAuth-only accounts if password login is expected.","Use a password manager to avoid typos; reset password when unsure.","Watch logs for repeated failures from one IP and apply rate limiting/firewalling.","Keep client sessions refreshed after password changes."],"tags":["authentication","security","login"],"backgroundTag":"authentication-required","analyzedSha":"f48d4b332127ad365ba256108799ca8f571d2dd5","analyzedAt":"2026-09-15T07:20:19.675Z","contentChangedAt":"2026-09-15T07:20:19.675Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}