nextcloud/server · error · NoValidCredentials

NoValidCredentials

Error message

NoValidCredentials

What it means

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.

Source

Thrown at core/src/services/WebAuthnAuthenticationService.ts:27

import { generateUrl } from '@nextcloud/router'
import { startAuthentication as startWebauthnAuthentication } from '@simplewebauthn/browser'
import logger from '../logger.js'

export class NoValidCredentials extends Error {}

/**
 * Start webautn authentication
 * This loads the challenge, connects to the authenticator and returns the repose that needs to be sent to the server.
 *
 * @param loginName Name to login
 */
export async function startAuthentication(loginName: string) {
	const url = generateUrl('/login/webauthn/start')

	const { data } = await Axios.post<PublicKeyCredentialRequestOptionsJSON>(url, { loginName })
	if (!data.allowCredentials || data.allowCredentials.length === 0) {
		logger.error('No valid credentials returned for webauthn')
		throw new NoValidCredentials()
	}
	return await startWebauthnAuthentication({ optionsJSON: data })
}

/**
 * Verify webauthn authentication
 *
 * @param authData The authentication data to sent to the server
 */
export async function finishAuthentication(authData: AuthenticationResponseJSON) {
	const url = generateUrl('/login/webauthn/finish')

	const { data } = await Axios.post(url, { data: JSON.stringify(authData) })
	return data
}

View on GitHub (pinned to ecdeb153ff)

Solutions

  1. Catch NoValidCredentials and fall back to the password (or another factor) login flow instead of showing a raw error
  2. Verify the loginName resolves to the account that actually has registered devices (use the uid shown in personal security settings)
  3. Enroll at least one security key under Personal info > Security before attempting webauthn login
  4. If devices should exist, check with the admin that they were not removed and that the user backend maps the login name correctly

Example fix

// before
const authData = await startAuthentication(loginName) // throws NoValidCredentials

// after
import { NoValidCredentials, startAuthentication } from '../services/WebAuthnAuthenticationService.js'
try {
	const authData = await startAuthentication(loginName)
} catch (e) {
	if (e instanceof NoValidCredentials) {
		showError(t('core', 'No security key registered for this account — use your password'))
		switchToPasswordFlow()
	} else throw e
}
Defensive patterns

Strategy: try-catch

Type guard

import { NoValidCredentials } from './WebAuthnAuthenticationService.js'

function isNoValidCredentials(e: unknown): e is NoValidCredentials {
	return e instanceof NoValidCredentials
}

Try / catch

try {
	const authData = await startAuthentication(loginName)
} catch (e) {
	if (e instanceof NoValidCredentials) {
		// no registered security key for this account — switch to password flow
	} else {
		throw e // transport/authenticator errors have different remedies
	}
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of nextcloud/server@ecdeb153ff (2026-08-17). Data as JSON: /api/errors/494564d119b49f4d. Report an issue: GitHub.