{"record":{"id":"bbf10d82ee875518","repo":"apereo/cas","slug":"provided-token-is-not-issued-by-and-does-not-belo","errorCode":null,"errorMessage":"Provided token  is not issued by and does not belong to ","messagePattern":"Provided token  is not issued by and does not belong to ","errorType":"exception","errorClass":"AuthenticationException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-passwordless-webflow/src/main/java/org/apereo/cas/web/flow/AcceptPasswordlessAuthenticationAction.java","lineNumber":69,"sourceCode":"        this.passwordlessTokenRepository = passwordlessTokenRepository;\n        this.authenticationSystemSupport = authenticationSystemSupport;\n        this.passwordlessUserAccountStore = passwordlessUserAccountStore;\n    }\n\n    @Override\n    protected @Nullable Event doExecuteInternal(final RequestContext requestContext) throws Throwable {\n        val passwordlessUserAccount = Objects.requireNonNull(PasswordlessWebflowUtils.getPasswordlessAuthenticationAccount(requestContext, PasswordlessUserAccount.class));\n        try {\n            val token = requestContext.getRequestParameters().getRequired(\"token\");\n            val passwordlessToken = passwordlessTokenRepository.findToken(passwordlessUserAccount.getUsername())\n                .orElseThrow(() -> new AuthenticationException(\"Unable to find passwordless token for \" + passwordlessUserAccount.getUsername()));\n            if (passwordlessToken.getToken().equalsIgnoreCase(token)) {\n                handlePasswordlessAuthenticationAttempt(requestContext, passwordlessUserAccount, passwordlessToken);\n                val finalEvent = super.doExecuteInternal(requestContext);\n                passwordlessTokenRepository.deleteToken(passwordlessToken);\n                return finalEvent;\n            }\n            throw new AuthenticationException(\"Provided token \" + token + \" is not issued by and does not belong to \" + passwordlessUserAccount.getUsername());\n        } catch (final Throwable e) {\n            LoggingUtils.error(LOGGER, e);\n            val attributes = new LocalAttributeMap<>();\n            attributes.put(\"error\", e);\n            val request = PasswordlessAuthenticationRequest.builder()\n                .username(passwordlessUserAccount.getUsername())\n                .build();\n            var account = passwordlessUserAccountStore.findUser(request);\n            account.ifPresent(o -> attributes.put(\"passwordlessAccount\", passwordlessUserAccount));\n            return eventFactory.event(this, CasWebflowConstants.TRANSITION_ID_AUTHENTICATION_FAILURE, attributes);\n        }\n    }\n\n    protected void handlePasswordlessAuthenticationAttempt(final RequestContext requestContext, final PasswordlessUserAccount principal,\n                                                           final PasswordlessAuthenticationToken token) throws Throwable {\n        val credential = new OneTimePasswordCredential(principal.getUsername(), token.getToken());\n        val service = WebUtils.getService(requestContext);\n        var authenticationResultBuilder = authenticationSystemSupport.handleInitialAuthenticationTransaction(service, credential);","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-passwordless-webflow/src/main/java/org/apereo/cas/web/flow/AcceptPasswordlessAuthenticationAction.java#L51-L87","documentation":"AuthenticationException thrown by AcceptPasswordlessAuthenticationAction when the token submitted in the request does not match the stored passwordless token retrieved for the user account. The action looks up the user's PasswordlessToken and requires an exact case-insensitive-equal match; any mismatch aborts the flow and surfaces an error event.","triggerScenarios":"User submits a token string in the passwordless webflow that differs from passwordlessToken.getToken() for the resolved passwordless user account (token typed incorrectly, stale token from a previous request, or token for a different user).","commonSituations":"User opens an old email/SMS link with an already-replaced token; user retypes the code with a typo; multiple passwordless requests invalidated each other; the repository returned a token generated after the user's submission.","solutions":["Request a new passwordless token and use the most recent one immediately.","Check that the link/code was not truncated by the mail/SMS client (whitespace or HTML encoding of the token).","Ensure the passwordless account lookup (username) matches the user who requested the token.","If tokens keep expiring, increase the token expiration policy in the passwordless configuration."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Compare tokens before invoking the action\nOptional<PasswordlessToken> tok = repo.findToken(username);\nif (tok.isEmpty() || !tok.get().getToken().equalsIgnoreCase(submittedToken)) {\n    return error(\"token mismatch\");\n}","typeGuard":null,"tryCatchPattern":"try { action.execute(ctx); } catch (AuthenticationException e) { flashError(\"invalid token; request a new one\"); return errorEvent; }","preventionTips":["Always use the most recently issued token/link.","Guard email/SMS rendering so token strings are not truncated or HTML-mangled.","Inform users that old codes become invalid when a new one is requested."],"tags":["authentication","one-time-token","webflow"],"backgroundTag":"invalid-argument-value","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"}