{"record":{"id":"7481c284b57a0801","repo":"apereo/cas","slug":"unable-to-locate-user-based-on-the-given-user-hand","errorCode":null,"errorMessage":"Unable to locate user based on the given user handle","messagePattern":"Unable to locate user based on the given user handle","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":60,"sourceCode":"        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    }\n}\n","sourceCodeStart":42,"sourceCodeEnd":75,"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#L42-L75","documentation":"After resolving the WebAuthn session, the action asks webAuthnCredentialRepository.getUsernameForUserHandle(userHandle) for the account tied to the WebAuthn user handle; when empty, the user record is unknown to the credential repository and the flow fails with authentication failure. The device's user handle maps to no known user.","triggerScenarios":"doExecuteInternal calls webAuthnCredentialRepository.getUsernameForUserHandle(session.get()) and the returned Optional is empty — the user handle in the session has no matching entry in the configured WebAuthn credential repository (in-memory, JSON, database, LDAP, etc.).","commonSituations":"WebAuthn registration records deleted or purged while a session/token still references them; user re-registered on a different backend so the old user handle no longer resolves; switched credential repository backends (e.g. in-memory to JDBC) losing prior registrations; multi-node setup with non-shared credential storage.","solutions":["Re-register the device: delete the stale registration and have the user enroll WebAuthn again so a valid user-handle/credential record exists in the repository.","Check the configured WebAuthn credential repository backend and verify the user handle exists there (query its storage directly); migrate data if you switched backends.","On clustered deployments, ensure all nodes share the same credential repository storage so getUsernameForUserHandle resolves consistently."],"exampleFix":"// before (records lost after switching to in-memory repo)\ncas.authn.mfa.web-authn.core.username-attribute-name=\n# no persistent registration storage\n\n// after: persist registrations so user handles resolve\ncas.authn.mfa.web-authn.json.location=/etc/cas/config/webauthn-accounts.json","handlingStrategy":"validation","validationCode":"// before the ceremony, verify the user handle resolves in the credential repository\nOptional<String> username = webAuthnCredentialRepository.getUsernameForUserHandle(userHandle);\nif (username.isEmpty()) {\n    // force re-registration of the WebAuthn device\n}","typeGuard":null,"tryCatchPattern":"try {\n    result = webAuthnCredentialRepository.getUsernameForUserHandle(session.get());\n} catch (Exception e) {\n    // repository backend unreachable: fall back to re-registration prompt\n}","preventionTips":["Use a persistent WebAuthn credential repository (JSON/JDBC/LDAP) rather than in-memory.","When migrating repository backends, copy existing registration records including user handles.","In clusters, ensure all nodes point at the same credential repository storage."],"tags":["webauthn","mfa","user-handle","credential-repository"],"backgroundTag":"record-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"}