{"record":{"id":"e115861a95e7869b","repo":"apereo/cas","slug":"authentication-throttling-rate-exceeds-the-de","errorCode":null,"errorMessage":"Authentication throttling rate [{}] exceeds the defined threshold [{}]","messagePattern":"Authentication throttling rate \\[(.+?)\\] exceeds the defined threshold \\[(.+?)\\]","errorType":"http","errorClass":null,"httpStatus":429,"severity":"warning","filePath":"support/cas-server-support-throttle-core/src/main/java/org/apereo/cas/throttle/AbstractThrottledSubmissionHandlerInterceptorAdapter.java","lineNumber":125,"sourceCode":"    protected boolean shouldResponseBeRecordedAsFailure(final HttpServletResponse response) {\n        val status = response.getStatus();\n        return status != HttpStatus.CREATED.value()\n            && status != HttpStatus.OK.value() && status != HttpStatus.FOUND.value();\n    }\n\n    protected void recordThrottle(final HttpServletRequest request) {\n    }\n\n    protected boolean calculateFailureThresholdRateAndCompare(final List<? extends ThrottledSubmission> failures) {\n        if (failures.size() >= 2) {\n            val lastTime = DateTimeUtils.dateOf(failures.getFirst().getValue()).getTime();\n            val secondToLastTime = DateTimeUtils.dateOf(failures.get(1).getValue()).getTime();\n            val difference = lastTime - secondToLastTime;\n            val rate = NUMBER_OF_MILLISECONDS_IN_SECOND / difference;\n            LOGGER.debug(\"Last attempt was at [{}] and the one before that was at [{}]. Difference is [{}] calculated as rate of [{}]\",\n                lastTime, secondToLastTime, difference, rate);\n            if (rate > getThresholdRate()) {\n                LOGGER.warn(\"Authentication throttling rate [{}] exceeds the defined threshold [{}]\", rate, getThresholdRate());\n                return true;\n            }\n        }\n        return false;\n    }\n\n    protected String getUsernameParameterFromRequest(final HttpServletRequest request) {\n        val throttle = getConfigurationContext().getCasProperties().getAuthn().getThrottle().getCore();\n        return request.getParameter(StringUtils.defaultIfBlank(throttle.getUsernameParameter(), \"username\"));\n    }\n\n    protected LocalDateTime getFailureInRangeCutOffDate() {\n        val throttle = getConfigurationContext().getCasProperties().getAuthn().getThrottle().getFailure();\n        return LocalDateTime.now(ZoneOffset.UTC).minusSeconds(throttle.getRangeSeconds());\n    }\n\n    protected void recordAuditAction(final HttpServletRequest request, final String actionName) {\n        val userToUse = getUsernameParameterFromRequest(request);","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-throttle-core/src/main/java/org/apereo/cas/throttle/AbstractThrottledSubmissionHandlerInterceptorAdapter.java#L107-L143","documentation":"calculateFailureThresholdRateAndCompare computes the instantaneous failure rate between the two most recent failed attempts (1 second divided by the millisecond difference). If that computed rate exceeds the configured threshold rate, this warning is logged and the request is throttled.","triggerScenarios":"Two consecutive failed authentication attempts recorded so close together that (1000ms / gapMs) is greater than cas.authn.throttle's threshold rate — e.g. failures within a few milliseconds to a few hundred milliseconds of each other.","commonSituations":"Automated scripts submitting rapid-fire login attempts; application retry loops retrying bad credentials immediately; extremely sensitive threshold configuration making any quick double-submit trip the limiter.","solutions":["Slow down or de-duplicate client-side retries of failed authentication.","Lower the configured threshold rate so only genuinely fast sequences trigger throttling.","Block or rate-limit the offending client at a proxy/WAF layer.","Review audit log timestamps to confirm whether the pattern is an attack."],"exampleFix":"// before\ncas.authn.throttle.failure.threshold=3\ncas.authn.throttle.failure.range-seconds=60\n// after: threshold rate tuned so normal retries aren't throttled\ncas.authn.throttle.failure.threshold=15\ncas.authn.throttle.failure.range-seconds=60","handlingStrategy":"validation","validationCode":"// client: enforce a minimum gap between authentication attempts\nif (lastAttempt != null && Instant.now().toEpochMilli() - lastAttempt < 1000)\n    Thread.sleep(1000);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Debounce client retries; never retry failed auth in a tight loop.","Calculate your effective threshold rate and test it before production.","Review audit failure timestamps to distinguish attack from misconfiguration."],"tags":["throttling","rate-limiting","threshold","authentication"],"backgroundTag":"rate-limit-exceeded","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}