{"record":{"id":"2d5dca21c01485d3","repo":"apereo/cas","slug":"throttling-submission-from-authentication-at","errorCode":null,"errorMessage":"Throttling submission from [{}]. Authentication attempt exceeds the failure threshold [{}]","messagePattern":"Throttling submission from \\[(.+?)\\]\\. Authentication attempt exceeds the failure 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":67,"sourceCode":"    @Override\n    public void afterPropertiesSet() {\n        val throttle = getConfigurationContext().getCasProperties().getAuthn().getThrottle().getFailure();\n        this.thresholdRate = (double) throttle.getThreshold() / throttle.getRangeSeconds();\n        LOGGER.trace(\"Calculated threshold rate as [{}]\", this.thresholdRate);\n    }\n\n    @Override\n    public final boolean preHandle(final @NonNull HttpServletRequest request,\n                                   final @NonNull HttpServletResponse response,\n                                   final @NonNull Object handler) {\n        if (isRequestIgnoredForThrottling(request, response)) {\n            LOGGER.trace(\"Letting the request through without throttling; No request filters support it\");\n            return true;\n        }\n\n        val throttled = throttleRequest(request, response) || exceedsThreshold(request);\n        if (throttled) {\n            LOGGER.warn(\"Throttling submission from [{}]. Authentication attempt exceeds the failure threshold [{}]\",\n                request.getRemoteAddr(), this.thresholdRate);\n            recordThrottle(request);\n            updateThrottledSubmission(request);\n            return configurationContext.getThrottledRequestResponseHandler().handle(request, response);\n        }\n        return true;\n    }\n\n    @Override\n    public final void postHandle(final @NonNull HttpServletRequest request, final @NonNull HttpServletResponse response,\n                                 final @NonNull Object handler, final ModelAndView modelAndView) {\n        if (isRequestIgnoredForThrottling(request, response)) {\n            LOGGER.trace(\"Skipping authentication throttling for requests; no filters support it.\");\n            return;\n        }\n\n        val recordEvent = shouldResponseBeRecordedAsFailure(response);\n        if (recordEvent) {","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-throttle-core/src/main/java/org/apereo/cas/throttle/AbstractThrottledSubmissionHandlerInterceptorAdapter.java#L49-L85","documentation":"AbstractThrottledSubmissionHandlerInterceptorAdapter.preHandle decides before authentication whether the request should be throttled. When throttleRequest or exceedsThreshold indicates the failure threshold is met, this warning logs the client's remote address and the configured threshold rate; the throttle is recorded, the submission updated, and the configured throttled request response handler rejects the request.","triggerScenarios":"preHandle finds the request's key already exceeds the failure threshold (via throttleRequest(request,response) or exceedsThreshold(request)) — i.e. too many failed authentications from the same username/IP within the configured rate window.","commonSituations":"Brute-force/credential-stuffing attempts against /login; misbehaving integration tests replaying failed logins; shared NAT IP causing many users to trip the per-IP threshold.","solutions":["Investigate the source address for attack activity and block it upstream if malicious.","Raise the threshold or shorten the range so legitimate users are not throttled.","Configure a custom ThrottledRequestResponseHandler to return an appropriate response (e.g. 429).","For shared NAT scenarios, switch the throttle key to username-based instead of IP-based."],"exampleFix":"// before: key by IP only (NAT problem)\ncas.authn.throttle.app-code=CAS\ncas.authn.throttle.failure.code=AuthenticationFailed\n// consider username-based throttle handler or raise threshold\ncas.authn.throttle.failure.threshold=20","handlingStrategy":"retry","validationCode":"// client: avoid rapid consecutive failed attempts\nif (lastAuthFailure != null && Duration.between(lastAuthFailure, Instant.now()).getSeconds() < 5)\n    throw new IllegalStateException(\"Wait before retrying authentication\");","typeGuard":null,"tryCatchPattern":"// back off when throttled\ntry {\n    casLogin(user, pass);\n} catch (HttpClientErrorException e) {\n    if (e.getStatusCode().value() == 429) {\n        Thread.sleep(backoffSeconds++ * 1000L);\n        casLogin(user, pass);\n    } else throw e;\n}","preventionTips":["Use per-username throttle keys to avoid NAT-shared-IP lockouts.","Deploy WAF/proxy rate limits upstream of CAS for abusive clients.","Monitor preHandle throttle warnings as a security signal."],"tags":["throttling","rate-limiting","authentication","prehandle"],"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"}