{"record":{"id":"59f54dd02ac01cfa","repo":"apereo/cas","slug":"unable-to-verify-provided-user-code","errorCode":null,"errorMessage":"Unable to verify provided user code ","messagePattern":"Unable to verify provided user code ","errorType":"exception","errorClass":"AuthenticationException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/web/controllers/ciba/OidcCibaController.java","lineNumber":143,"sourceCode":"    @Operation(summary = \"Verify backchannel verification request\",\n        parameters = {\n            @Parameter(name = \"clientId\", in = ParameterIn.PATH, description = \"Client ID\"),\n            @Parameter(name = \"requestId\", in = ParameterIn.PATH, description = \"Request ID\"),\n            @Parameter(name = \"userCode\", in = ParameterIn.QUERY, required = false, description = \"Request ID\")\n        })\n    public ResponseEntity verifyBackchannelVerificationRequest(\n        @RequestParam(value = \"userCode\", required = false)\n        final String userCode,\n        @PathVariable final String clientId,\n        @PathVariable final String requestId) throws Throwable {\n        try {\n            val registeredService = findRegisteredService(clientId);\n            val cibaRequest = fetchOidcCibaRequest(requestId);\n            if (cibaRequest.getAuthentication().containsAttribute(OidcConstants.USER_CODE)) {\n                val userCodeValues = cibaRequest.getAuthentication().getAttributes().get(OidcConstants.USER_CODE)\n                    .stream().map(Object::toString).filter(StringUtils::isNotBlank).toList();\n                if (StringUtils.isBlank(userCode) || !userCodeValues.contains(userCode)) {\n                    throw new AuthenticationException(\"Unable to verify provided user code \" + userCode);\n                }\n            }\n\n            for (val handler : tokenDeliveryHandlers) {\n                if (BeanSupplier.isNotProxy(handler) && handler.supports(registeredService)) {\n                    handler.deliver(registeredService, cibaRequest);\n                }\n            }\n\n            val model = new LinkedHashMap<String, Object>();\n            model.put(\"registeredService\", registeredService);\n            model.put(\"cibaRequest\", cibaRequest);\n            return ResponseEntity.ok(model);\n        } catch (final Exception e) {\n            LoggingUtils.error(LOGGER, e);\n            return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();\n        }\n    }","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-oidc-core-api/src/main/java/org/apereo/cas/oidc/web/controllers/ciba/OidcCibaController.java#L125-L161","documentation":"OidcCibaController.verifyBackchannelVerificationRequest throws AuthenticationException with this message when the user code supplied during the backchannel authentication verification step does not match the user code stored on the CIBA request (or is blank while a user code is required). This guards the authentication-device flow against binding the wrong user's consent.","triggerScenarios":"The CIBA request's authentication attributes contain OidcConstants.USER_CODE, and the submitted userCode is blank or not among the stored non-blank user code values; invoked from the CIBA verification endpoint.","commonSituations":"End user mistypes the user code shown on the authentication device; user code expired/rotated between request creation and verification; verification UI submitted an empty field; user code from a different CIBA transaction.","solutions":["Have the user re-enter the exact user code displayed by the relying party","Confirm the verification request uses the same requestId/auth request that originally carried the user code","Check for trailing whitespace/case differences between submitted and stored codes","If user codes are one-time/expiring, re-initiate the backchannel authentication request"],"exampleFix":"// before: blank or mismatched code submitted\nverify(requestId, userCode=\"\")  // AuthenticationException\n// after: validate before calling\nif (StringUtils.isNotBlank(userCode)) { verify(requestId, userCode.trim()); } else { rePromptForUserCode(); }","handlingStrategy":"validation","validationCode":"if (StringUtils.isBlank(userCode) || !storedUserCodes.contains(userCode)) {\n    throw new BadRequestException(\"user_code does not match the pending CIBA request\");\n}","typeGuard":null,"tryCatchPattern":"try { controller.verifyBackchannelVerificationRequest(request, requestId, clientId, userCode); } catch (AuthenticationException e) { if (e.getMessage().startsWith(\"Unable to verify provided user code\")) { showUserCodeRetryPrompt(); return; } throw e; }","preventionTips":["Display the user code clearly and enforce exact re-entry on the device UI","Trim/canonicalize user codes before submission","Keep the verification session tied to the same requestId as the original CIBA request","Expire and re-issue user codes rather than allowing unlimited retries"],"tags":["oidc","ciba","user-code","authentication"],"backgroundTag":"authentication-required","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"}