{"record":{"id":"125d6a75466a86e8","repo":"apereo/cas","slug":"credential-principal-does-not-match-authentic","errorCode":null,"errorMessage":"Credential principal [{}] does not match authentication principal [{}]","messagePattern":"Credential principal \\[(.+?)\\] does not match authentication principal \\[(.+?)\\]","errorType":"exception","errorClass":"MultifactorAuthenticationFailedException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-simple-mfa-core/src/main/java/org/apereo/cas/mfa/simple/CasSimpleMultifactorAuthenticationHandler.java","lineNumber":73,"sourceCode":"    }\n\n    @Override\n    public boolean supports(final Class<? extends Credential> clazz) {\n        return CasSimpleMultifactorTokenCredential.class.isAssignableFrom(clazz);\n    }\n\n    @Override\n    protected AuthenticationHandlerExecutionResult doAuthentication(final Credential credential,\n                                                                    final Service service) throws Exception {\n        return FunctionUtils.doAndThrow(() -> {\n            val tokenCredential = (CasSimpleMultifactorTokenCredential) credential;\n            val credentialPrincipal = multifactorAuthenticationService.fetch(tokenCredential);\n            val resolvedPrincipal = resolvePrincipal(applicationContext, credentialPrincipal);\n            val principal = multifactorAuthenticationService.validate(resolvedPrincipal, tokenCredential);\n\n            val activePrincipal = findActivePrincipal();\n            if (!principal.equals(activePrincipal)) {\n                LOGGER.warn(\"Credential principal [{}] does not match authentication principal [{}]\",\n                    principal.getId(), activePrincipal.getId());\n                throw new MultifactorAuthenticationFailedException(\"Failed to authenticate code \" + tokenCredential.getId());\n            }\n            return createHandlerResult(tokenCredential, principal);\n        }, MultifactorAuthenticationFailedException::new);\n    }\n\n    protected Principal findActivePrincipal() {\n        val authentication = Objects.requireNonNull(WebUtils.getInProgressAuthentication());\n        val principal = authentication.getPrincipal();\n        return principal.getOwner();\n    }\n}\n","sourceCodeStart":55,"sourceCodeEnd":87,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-simple-mfa-core/src/main/java/org/apereo/cas/mfa/simple/CasSimpleMultifactorAuthenticationHandler.java#L55-L87","documentation":"CasSimpleMultifactorAuthenticationHandler.doAuthentication() compares the principal stored on the submitted MFA token credential with the principal of the currently authenticated user. When they differ, it logs this warning and throws MultifactorAuthenticationFailedException, rejecting the token. This prevents using a one-time code issued to a different user.","triggerScenarios":"Submitting a simple-MFA token code that was issued for another principal (or whose stored principal was mutated) during the multifactor authentication step of a different user's session.","commonSituations":"User pastes a code from a colleague's or another tab's email/SMS; ticket-registry data corruption or shared token IDs across environments; session switch where the browser retains another account's pending code.","solutions":["Request a fresh token code for the currently authenticated user and submit that one","Ensure each browser session completes its own MFA flow; do not reuse codes across sessions/accounts","Check ticket registry consistency if tokens appear cross-wired (shared Redis/Hazelcast keys across environments)","Verify custom principal resolution in the MFA service does not alter the principal identity between issuance and validation"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Before submitting, confirm the code belongs to the current session/user\nif (!mfaContext.getTokenIdFor(principal.getId()).equals(submittedTokenId)) {\n    throw new IllegalStateException(\"Token does not belong to current user\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    handlerResult = handler.authenticate(credential, service);\n} catch (MultifactorAuthenticationFailedException e) {\n    // prompt user to request a new code\n    return mfaFlow.requestNewToken(principal);\n}","preventionTips":["Never reuse MFA codes across accounts or browser sessions","Complete each MFA flow in the session that initiated it","Monitor for repeated mismatches as a possible token-confusion or replay attack"],"tags":["mfa","authentication","principal-mismatch","security"],"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"}