{"record":{"id":"687801307e5628fd","repo":"apereo/cas","slug":"failed-to-authenticate-code-687801","errorCode":null,"errorMessage":"Failed to authenticate code ","messagePattern":"Failed to authenticate code ","errorType":"exception","errorClass":"FailedLoginException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-simple-mfa-core/src/main/java/org/apereo/cas/mfa/simple/validation/BaseCasSimpleMultifactorAuthenticationService.java","lineNumber":37,"sourceCode":" * @since 7.2.0\n */\n@Slf4j\n@RequiredArgsConstructor\npublic abstract class BaseCasSimpleMultifactorAuthenticationService implements CasSimpleMultifactorAuthenticationService {\n    protected final TicketRegistry ticketRegistry;\n\n    @Override\n    public CasSimpleMultifactorAuthenticationTicket getMultifactorAuthenticationTicket(final CasSimpleMultifactorTokenCredential credential) {\n        val tokenId = normalize(credential.getId());\n        return ticketRegistry.getTicket(tokenId, CasSimpleMultifactorAuthenticationTicket.class);\n    }\n\n    protected Principal validateTokenForPrincipal(final Principal resolvedPrincipal, final CasSimpleMultifactorAuthenticationTicket acct)\n        throws FailedLoginException {\n        if (!acct.getProperties().containsKey(CasSimpleMultifactorAuthenticationConstants.PROPERTY_PRINCIPAL)) {\n            LOGGER.warn(\"Unable to locate principal for token [{}]\", acct.getId());\n            deleteToken(acct);\n            throw new FailedLoginException(\"Failed to authenticate code \" + acct.getId());\n        }\n        val principal = (Principal) acct.getProperties().get(CasSimpleMultifactorAuthenticationConstants.PROPERTY_PRINCIPAL);\n        if (!principal.equals(resolvedPrincipal)) {\n            LOGGER.warn(\"Principal assigned to token [{}] is unauthorized for token [{}]\", principal.getId(), acct.getId());\n            deleteToken(acct);\n            throw new FailedLoginException(\"Failed to authenticate code \" + acct.getId());\n        }\n        return principal;\n    }\n\n    protected static String normalize(final String tokenId) {\n        if (!tokenId.startsWith(CasSimpleMultifactorAuthenticationTicket.PREFIX)) {\n            return CasSimpleMultifactorAuthenticationTicket.PREFIX + UniqueTicketIdGenerator.SEPARATOR + tokenId;\n        }\n        return tokenId;\n    }\n\n    protected void deleteToken(final CasSimpleMultifactorAuthenticationTicket acct) {","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-simple-mfa-core/src/main/java/org/apereo/cas/mfa/simple/validation/BaseCasSimpleMultifactorAuthenticationService.java#L19-L55","documentation":"BaseCasSimpleMultifactorAuthenticationService.validateTokenForPrincipal throws FailedLoginException \"Failed to authenticate code <id>\" when the stored MFA authentication ticket has no PROPERTY_PRINCIPAL entry. Without the principal recorded on the token, the service cannot confirm the code belongs to the presenting user, so it deletes the token and fails the attempt.","triggerScenarios":"validate -> validateTokenForPrincipal when acct.getProperties() lacks CasSimpleMultifactorAuthenticationConstants.PROPERTY_PRINCIPAL — i.e., the token was created without the principal property, was corrupted, or is a fabricated/foreign ticket ID.","commonSituations":"A token was minted by a path that did not attach the principal property (custom/REST flows); ticket-registry data loss or serialization issues stripping properties; attacker probing with guessed token IDs; version-upgrade migration where older tokens lack the property.","solutions":["Regenerate the MFA token through the standard flow so the principal property is set","Inspect the ticket registry record for the token and confirm PROPERTY_PRINCIPAL exists","Upgrade/align all CAS nodes to the same version so ticket serialization is consistent","Clear stale/corrupted tokens from the registry and have the user restart the MFA step"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// verify the token record actually carries the principal property before validating\nvar acct = (CasSimpleMultifactorAuthenticationTicket) ticketRegistry.getTicket(tokenId);\nif (acct == null || !acct.getProperties().containsKey(\n        CasSimpleMultifactorAuthenticationConstants.PROPERTY_PRINCIPAL)) {\n    throw new IllegalStateException(\"Token missing principal property; request a new code\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    principal = mfaService.validate(resolvedPrincipal, credential);\n} catch (FailedLoginException e) {\n    LOGGER.warn(\"MFA token invalid ({}); restarting MFA with a fresh code\", e.getMessage());\n    restartMfaFlow(resolvedPrincipal);\n}","preventionTips":["Always mint simple-MFA tokens via the standard CAS flow so PROPERTY_PRINCIPAL is set","Keep all CAS nodes on the same version to avoid ticket-registry serialization gaps","Treat \"principal missing\" tokens as stale and never retry them"],"tags":["mfa","one-time-token","ticket-registry","failed-login"],"backgroundTag":"mfa-code-validation-failed","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"}