{"record":{"id":"494564d119b49f4d","repo":"nextcloud/server","slug":"novalidcredentials","errorCode":null,"errorMessage":"NoValidCredentials","messagePattern":"NoValidCredentials","errorType":"exception","errorClass":"NoValidCredentials","httpStatus":null,"severity":"error","filePath":"core/src/services/WebAuthnAuthenticationService.ts","lineNumber":27,"sourceCode":"import { generateUrl } from '@nextcloud/router'\nimport { startAuthentication as startWebauthnAuthentication } from '@simplewebauthn/browser'\nimport logger from '../logger.js'\n\nexport class NoValidCredentials extends Error {}\n\n/**\n * Start webautn authentication\n * This loads the challenge, connects to the authenticator and returns the repose that needs to be sent to the server.\n *\n * @param loginName Name to login\n */\nexport async function startAuthentication(loginName: string) {\n\tconst url = generateUrl('/login/webauthn/start')\n\n\tconst { data } = await Axios.post<PublicKeyCredentialRequestOptionsJSON>(url, { loginName })\n\tif (!data.allowCredentials || data.allowCredentials.length === 0) {\n\t\tlogger.error('No valid credentials returned for webauthn')\n\t\tthrow new NoValidCredentials()\n\t}\n\treturn await startWebauthnAuthentication({ optionsJSON: data })\n}\n\n/**\n * Verify webauthn authentication\n *\n * @param authData The authentication data to sent to the server\n */\nexport async function finishAuthentication(authData: AuthenticationResponseJSON) {\n\tconst url = generateUrl('/login/webauthn/finish')\n\n\tconst { data } = await Axios.post(url, { data: JSON.stringify(authData) })\n\treturn data\n}\n","sourceCodeStart":9,"sourceCodeEnd":43,"githubUrl":"https://github.com/nextcloud/server/blob/ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3/core/src/services/WebAuthnAuthenticationService.ts#L9-L43","documentation":"NoValidCredentials (exported class in core/src/services/WebAuthnAuthenticationService.ts) is thrown by startAuthentication() when POST /login/webauthn/start succeeds but the returned PublicKeyCredentialRequestOptionsJSON has an empty or missing allowCredentials list. That means the server found no registered WebAuthn devices for the given login name, so there is nothing for the browser/authenticator to assert against.","triggerScenarios":"Calling startAuthentication(loginName) for an account with zero registered security keys; devices previously removed by the user or an admin; loginName not matching the account (server looks up devices per uid — trying an email alias when only the uid has registrations); user backend (e.g. LDAP) not resolving the name to the stored uid.","commonSituations":"Login page offering 'Sign in with security key' to every user, including those who never enrolled one; user got new hardware and admin wiped old credentials; typo/wrong identifier passed as loginName; testing webauthn login on an account with no device registered.","solutions":["Catch NoValidCredentials and fall back to the password (or another factor) login flow instead of showing a raw error","Verify the loginName resolves to the account that actually has registered devices (use the uid shown in personal security settings)","Enroll at least one security key under Personal info > Security before attempting webauthn login","If devices should exist, check with the admin that they were not removed and that the user backend maps the login name correctly"],"exampleFix":"// before\nconst authData = await startAuthentication(loginName) // throws NoValidCredentials\n\n// after\nimport { NoValidCredentials, startAuthentication } from '../services/WebAuthnAuthenticationService.js'\ntry {\n\tconst authData = await startAuthentication(loginName)\n} catch (e) {\n\tif (e instanceof NoValidCredentials) {\n\t\tshowError(t('core', 'No security key registered for this account — use your password'))\n\t\tswitchToPasswordFlow()\n\t} else throw e\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"import { NoValidCredentials } from './WebAuthnAuthenticationService.js'\n\nfunction isNoValidCredentials(e: unknown): e is NoValidCredentials {\n\treturn e instanceof NoValidCredentials\n}","tryCatchPattern":"try {\n\tconst authData = await startAuthentication(loginName)\n} catch (e) {\n\tif (e instanceof NoValidCredentials) {\n\t\t// no registered security key for this account — switch to password flow\n\t} else {\n\t\tthrow e // transport/authenticator errors have different remedies\n\t}\n}","preventionTips":["Offer the security-key flow only after confirming the account has registered webauthn devices (capabilities/session info)","Always pair webauthn login with a password fallback path","Pass the exact account uid as loginName — aliases may resolve to an account with no devices"],"tags":["webauthn","login","security-key","authentication","typescript"],"backgroundTag":"webauthn-no-registered-credential","analyzedSha":"ecdeb153ffdf227235c9a7e2d13dbe0f9c817bc3","analyzedAt":"2026-08-17T01:36:13.386Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}