{"record":{"id":"eaa533e8284396b8","repo":"apereo/cas","slug":"unable-to-locate-principal-for-token","errorCode":null,"errorMessage":"Unable to locate principal for token [{}]","messagePattern":"Unable to locate principal for token \\[(.+?)\\]","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":35,"sourceCode":" *\n * @author Misagh Moayyed\n * @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    }","sourceCodeStart":17,"sourceCodeEnd":53,"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#L17-L53","documentation":"BaseCasSimpleMultifactorAuthenticationService.validateTokenForPrincipal() requires the CasSimpleMultifactorAuthenticationTicket to carry a PROPERTY_PRINCIPAL attribute. If the ticket has no principal property, it logs this warning, deletes the token from the ticket registry, and throws FailedLoginException. The token is unusable because there is no identity to compare against.","triggerScenarios":"Validating a simple-MFA token whose authentication ticket was created without the principal property — e.g. a corrupted or manually fabricated ticket, or a ticket from an older/CAS version whose properties map lacks the principal entry.","commonSituations":"Ticket registry entries migrated from a different CAS version missing new properties; direct manipulation or partial serialization of ticket data in an external store (Redis/JDBC); bug in custom code constructing the MFA ticket.","solutions":["Discard the invalid code and restart the MFA flow to mint a new token with the principal property","Inspect the ticket registry entry for PROPERTY_PRINCIPAL and remove stale/corrupt entries","Check for ticket-registry data from an incompatible CAS version and flush the registry","Review any custom code that creates CasSimpleMultifactorAuthenticationTicket instances to ensure the principal property is always set"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"CasSimpleMultifactorAuthenticationTicket t =\n    (CasSimpleMultifactorAuthenticationTicket) ticketRegistry.getTicket(tokenId);\nif (t != null && !t.getProperties().containsKey(\n        CasSimpleMultifactorAuthenticationConstants.PROPERTY_PRINCIPAL)) {\n    // token is corrupt; require a new one\n}","typeGuard":null,"tryCatchPattern":"try {\n    service.validateTokenForPrincipal(resolvedPrincipal, ticket);\n} catch (FailedLoginException e) {\n    // reject code and restart MFA flow\n}","preventionTips":["Flush ticket registries after CAS version upgrades","Never hand-craft or edit ticket data in external stores","Ensure any custom ticket-creation code sets PROPERTY_PRINCIPAL"],"tags":["mfa","tickets","token-validation","security"],"backgroundTag":"invalid-token","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"}