{"record":{"id":"dd4b1f63f578a3e7","repo":"apereo/cas","slug":"unable-to-locate-existing-session-from-the-current","errorCode":null,"errorMessage":"Unable to locate existing session from the current token [{}]","messagePattern":"Unable to locate existing session from the current token \\[(.+?)\\]","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"support/cas-server-support-webauthn-core-webflow/src/main/java/org/apereo/cas/webauthn/web/flow/WebAuthnValidateSessionCredentialTokenAction.java","lineNumber":55,"sourceCode":"\n    protected final TenantExtractor tenantExtractor;\n    \n    @Override\n    protected @Nullable Event doExecuteInternal(final RequestContext requestContext) {\n        val request = WebUtils.getHttpServletRequestFromExternalWebflowContext(requestContext);\n        val token = request.getParameter(\"token\");\n        if (StringUtils.isBlank(token)) {\n            LOGGER.warn(\"Missing web authn token from the request\");\n            return eventFactory.event(this, CasWebflowConstants.TRANSITION_ID_AUTHENTICATION_FAILURE);\n        }\n\n        LOGGER.debug(\"Received web authn token [{}]\", token);\n        val credential = new WebAuthnCredential(token);\n        WebUtils.putCredential(requestContext, credential);\n\n        val session = sessionManager.getSession(request, WebAuthnCredential.from(credential));\n        if (session.isEmpty()) {\n            LOGGER.warn(\"Unable to locate existing session from the current token [{}]\", token);\n            return eventFactory.event(this, CasWebflowConstants.TRANSITION_ID_AUTHENTICATION_FAILURE);\n        }\n        val result = webAuthnCredentialRepository.getUsernameForUserHandle(session.get());\n        if (result.isEmpty()) {\n            LOGGER.warn(\"Unable to locate user based on the given user handle\");\n            return eventFactory.event(this, CasWebflowConstants.TRANSITION_ID_AUTHENTICATION_FAILURE);\n        }\n        val username = result.get();\n        return FunctionUtils.doUnchecked(() -> {\n            val authentication = DefaultAuthenticationBuilder.newInstance()\n                .addCredential(credential)\n                .setPrincipal(principalFactory.createPrincipal(username))\n                .build();\n            LOGGER.debug(\"Finalized authentication attempt based on [{}]\", authentication);\n            WebUtils.putAuthentication(authentication, requestContext);\n            return eventFactory.event(this, CasWebflowConstants.TRANSITION_ID_FINALIZE);\n        });\n    }","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-webauthn-core-webflow/src/main/java/org/apereo/cas/webauthn/web/flow/WebAuthnValidateSessionCredentialTokenAction.java#L37-L73","documentation":"A WebAuthn token was provided, but sessionManager.getSession(request, ...) for the token's derived identity returns empty, so the action cannot correlate the token to an existing server-side WebAuthn session and fails authentication. The token references a session CAS no longer holds.","triggerScenarios":"In doExecuteInternal, after building WebAuthnCredential from the token, WebAuthnCredential.from(credential) is used to look up the managed session; session.isEmpty() fires when the session expired, was evicted (restart or session store flush), or the token was issued by a different CAS node without shared session storage.","commonSituations":"User delays and the WebAuthn session times out; CAS restarted or session store (e.g. in-memory, Redis without proper persistence/TTL config) lost entries; load-balanced CAS without sticky sessions or shared session backend.","solutions":["Restart the WebAuthn MFA flow from the login page to obtain a fresh token and session.","If running multiple CAS nodes, configure a shared session store (e.g. distributed sessions via Redis/Hazelcast) or sticky sessions so getSession can find the token's session.","Increase the WebAuthn/session timeout configuration if legitimate users take too long to complete the ceremony."],"exampleFix":"// before (in-memory session per node)\n// no shared session config\n\n// after: enable shared session storage across CAS nodes\n# e.g. spring session backed by redis\nspring.session.store-type=redis\nspring.redis.host=redis.internal","handlingStrategy":"fallback","validationCode":"// before starting the WebAuthn ceremony, confirm an active session exists server-side\nif (!casSessionStore.exists(webAuthnSessionKey)) {\n  // redirect user to re-initiate the MFA flow instead of failing\n}","typeGuard":null,"tryCatchPattern":"try {\n    var session = sessionManager.getSession(request, WebAuthnCredential.from(credential));\n} catch (Exception e) {\n    // fall back to restarting the WebAuthn flow with a fresh token\n}","preventionTips":["Use shared session storage or sticky sessions in multi-node CAS deployments.","Size session/TTL timeouts so users can realistically complete the WebAuthn ceremony.","Treat CAS restarts as invalidating in-flight WebAuthn sessions; don't reuse old links."],"tags":["webauthn","mfa","session-expired","webflow"],"backgroundTag":"session-not-found","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"}