{"record":{"id":"36297f46527e80c8","repo":"apereo/cas","slug":"unable-to-verify-qr-code","errorCode":null,"errorMessage":"Unable to verify QR code ","messagePattern":"Unable to verify QR code ","errorType":"exception","errorClass":"FailedLoginException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-qr-authentication/src/main/java/org/apereo/cas/qr/authentication/QRAuthenticationTokenAuthenticationHandler.java","lineNumber":63,"sourceCode":"    @Override\n    protected AuthenticationHandlerExecutionResult doAuthentication(final Credential credential, final Service service) throws GeneralSecurityException {\n        val tokenCredential = (QRAuthenticationTokenCredential) credential;\n        try {\n            LOGGER.debug(\"Received token [{}]\", tokenCredential.getId());\n\n            val request = QRAuthenticationTokenValidationRequest.builder()\n                .token(tokenCredential.getId())\n                .registeredService(Optional.empty())\n                .deviceId(tokenCredential.getDeviceId())\n                .build();\n\n            val result = tokenValidatorService.validate(request);\n            val principal = result.getAuthentication().getPrincipal();\n            return createHandlerResult(tokenCredential, principal);\n        } catch (final Exception e) {\n            LoggingUtils.error(LOGGER, e);\n        }\n        throw new FailedLoginException(\"Unable to verify QR code \" + tokenCredential.getId());\n    }\n}\n\n","sourceCodeStart":45,"sourceCodeEnd":67,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-qr-authentication/src/main/java/org/apereo/cas/qr/authentication/QRAuthenticationTokenAuthenticationHandler.java#L45-L67","documentation":"FailedLoginException thrown by QRAuthenticationTokenAuthenticationHandler.doAuthentication after any exception occurs while validating the QR token credential. The handler delegates to QRAuthenticationTokenValidatorService.validate; on failure it logs the cause and always throws this FailedLoginException carrying the credential id.","triggerScenarios":"A QR login token credential fails validation: token expired, token's TGT no longer in the ticket registry, principal/issuer/device-id mismatch, device not authorized, or the JWT itself is malformed/untrusted — any Exception inside tokenValidatorService.validate(request) leads here.","commonSituations":"User scans an expired QR code; TGT expired and evicted from ticketRegistry; CAS server prefix changed so issuer no longer matches; device re-registered/deauthorized; clock skew between nodes; token from a different CAS environment.","solutions":["Regenerate/refresh the QR code and scan it promptly (check the token TTL in QR authentication properties).","Read the logged underlying exception (LoggingUtils.error output) to identify the exact validation failure.","Confirm cas.server.prefix matches the issuer used when the QR token was minted.","Verify the device id is still authorized (deviceRepository) and that ticketRegistry is shared/healthy in clustered deployments."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Pre-validate token freshness client-side before submitting\nboolean expired = Instant.now().isAfter(tokenExpiryInstant);\nif (expired) { refreshQrCode(); }","typeGuard":null,"tryCatchPattern":"try { handler.authenticate(qrTokenCredential); } catch (FailedLoginException e) { LOGGER.warn(\"QR login rejected: {}\", e.getMessage()); return errorEvent(\"qr.login.failed\"); }","preventionTips":["Auto-refresh the QR image before its token expires.","Keep server clocks NTP-synchronized.","Keep cas.server.prefix stable; monitor the validator's logged root cause."],"tags":["qr-authentication","token-validation","authentication"],"backgroundTag":"jwt-token-expired","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"}