{"record":{"id":"a1db1eb64266557d","repo":"apereo/cas","slug":"interrupt-response-has-blocked-the-authentication","errorCode":null,"errorMessage":"Interrupt response has blocked the authentication flow","messagePattern":"Interrupt response has blocked the authentication flow","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"support/cas-server-support-interrupt-webflow/src/main/java/org/apereo/cas/interrupt/webflow/actions/FinalizeInterruptFlowAction.java","lineNumber":43,"sourceCode":"public class FinalizeInterruptFlowAction extends BaseCasWebflowAction {\n    private final InterruptTrackingEngine interruptTrackingEngine;\n\n    @Override\n    protected @Nullable Event doExecuteInternal(final RequestContext requestContext) throws Throwable {\n        val response = InterruptUtils.getInterruptFrom(requestContext);\n        if (response.isBlock() && !requestContext.getRequestParameters().contains(\"link\")) {\n            val registeredService = WebUtils.getRegisteredService(requestContext);\n            val accessUrl = Optional.ofNullable(registeredService)\n                .map(service -> service.getAccessStrategy().getUnauthorizedRedirectUrl())\n                .orElse(null);\n            if (accessUrl != null) {\n                val url = accessUrl.toURL().toExternalForm();\n                val externalContext = requestContext.getExternalContext();\n                externalContext.requestExternalRedirect(url);\n                externalContext.recordResponseComplete();\n                return eventFactory.event(this, CasWebflowConstants.TRANSITION_ID_STOP);\n            }\n            LOGGER.warn(\"Interrupt response has blocked the authentication flow\");\n            throw UnauthorizedServiceException.denied(\"Rejected\");\n        }\n\n        if (requestContext.getRequestParameters().contains(\"link\")) {\n            val link = requestContext.getRequestParameters().get(\"link\");\n            LOGGER.debug(\"Finalizing interrupt flow with link [{}]\", link);\n            val validLink = response.getLinks().containsValue(link);\n            if (!validLink) {\n                LOGGER.warn(\"Link [{}] is not valid and is not part of the interrupt response\", link);\n                throw UnauthorizedServiceException.denied(\"Rejected\");\n            }\n        }\n        \n        val authentication = WebUtils.getAuthentication(requestContext);\n        interruptTrackingEngine.trackInterrupt(requestContext, response);\n        WebUtils.putAuthentication(authentication, requestContext);\n        WebUtils.putInterruptAuthenticationFlowFinalized(requestContext);\n        return success();","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-interrupt-webflow/src/main/java/org/apereo/cas/interrupt/webflow/actions/FinalizeInterruptFlowAction.java#L25-L61","documentation":"FinalizeInterruptFlowAction checks the interrupt response's execute behavior; when the user was instructed to acknowledge/blocked and the flow must not continue, CAS logs 'Interrupt response has blocked the authentication flow' and throws UnauthorizedServiceException.denied(\"Rejected\"), aborting the webflow. This is the enforcement point of CAS's interrupt (notification/forced-action) feature.","triggerScenarios":"A user finishes the interrupt screen with a response whose policy blocks continuation (e.g. required terms not accepted, mandatory notification not acknowledged, or a block URL configured — in the shown source an external redirect to accessUrl occurs for a block URL; otherwise the warn/exception path fires).","commonSituations":"Admins enabling forced interrupt messages (usage policy, terms of use) that users must accept; service access denied until the user completes the required interrupt action.","solutions":["Have the user accept the required interrupt message/options on the interrupt screen","Review the service's interrupt policy (WebflowInterruptAttribute/registered service interrupt settings) if blocking is unintended","Check the interrupt response stored for the user and remove stale blocked responses if the policy has changed","Disable the interrupt feature for the service if it should not be enforced"],"exampleFix":"// before (service registered with mandatory interrupt the user never accepted)\n\"interrupt\": true\n// after (interrupt satisfied via accepted response or disabled)\n\"interrupt\": false","handlingStrategy":"fallback","validationCode":"// check the user's interrupt response state before entering the flow\nval response = interruptInformer.findInterruptResponse(authentication, service);\nif (response != null && response.isBlocked()) {\n    // do not attempt login; route user to acknowledgment screen\n}","typeGuard":null,"tryCatchPattern":"try { flowExecutor.execute(...); } catch (UnauthorizedServiceException e) { LOGGER.info(\"Interrupt blocked flow for user\"); redirectToInterruptScreen(); }","preventionTips":["Inform users they must accept interrupt messages to proceed","Keep interrupt messages simple and mandatory-only where possible","Review registered service interrupt policies before enabling","Catch UnauthorizedServiceException in protocol adapters to return clean errors"],"tags":["interrupt","webflow","unauthorized"],"backgroundTag":"permission-denied","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"}