nextauthjs/next-auth · error · WebAuthnVerificationError
WebAuthn authentication response could not be verified
Error message
WebAuthn authentication response could not be verified
What it means
The @simplewebauthn/server verifyAuthenticationResponse returned verified:false, meaning the assertion failed cryptographic or challenge verification. The library wraps this as a WebAuthnVerificationError.
Source
Thrown at packages/core/src/lib/utils/webauthn-utils.ts:264
try {
const relayingParty = provider.getRelayingParty(options, request)
verification = await provider.simpleWebAuthn.verifyAuthenticationResponse({
...provider.verifyAuthenticationOptions,
expectedChallenge,
response: data as AuthenticationResponseJSON,
authenticator: fromAdapterAuthenticator(authenticator),
expectedOrigin: relayingParty.origin,
expectedRPID: relayingParty.id,
})
} catch (e: any) {
throw new WebAuthnVerificationError(e)
}
const { verified, authenticationInfo } = verification
// Make sure the response was verified
if (!verified) {
throw new WebAuthnVerificationError(
"WebAuthn authentication response could not be verified"
)
}
// Update authenticator counter
try {
const { newCounter } = authenticationInfo
await adapter.updateAuthenticatorCounter(
authenticator.credentialID,
newCounter
)
} catch (e: any) {
throw new AdapterError(
`Failed to update authenticator counter. This may cause future authentication attempts to fail. ${JSON.stringify(
{
credentialID,
oldCounter: authenticator.counter,
newCounter: authenticationInfo.newCounter,View on GitHub (pinned to a1a16a5a77)
Solutions
- Verify WebAuthnProvider rpID and origin match the domain the client used
- Ensure the challenge cookie from startAuthentication still exists and matches at verify time
- Confirm the authenticator record's publicKey matches the credential being used
- Check @simplewebauthn/server version compatibility with the response format
Example fix
// before
WebAuthnProvider({ id: "example.com" }) // client on localhost
// after
WebAuthnProvider({ id: "localhost", origin: "http://localhost:3000" }) Defensive patterns
Strategy: try-catch
Validate before calling
// pre-check config consistency console.assert(provider.rpID === new URL(clientOrigin).hostname, 'rpID must match client origin')
Try / catch
try {
await verifyAuthenticate(data)
} catch (e) {
if (e instanceof WebAuthnVerificationError) {
// reject login, clear challenge cookie, log for security review
return new Response('Verification failed', { status: 401 })
}
throw e
} Prevention
- Keep rpID and origin aligned with the deployment domain per environment
- Never reuse or cache challenge cookies across ceremonies
- Keep @simplewebauthn/server and the provider versions in sync
- Monitor verification failures as potential clone/attack signals
When it happens
Trigger: verifyAuthenticate receives an assertion whose challenge does not match the stored cookie challenge, origin/rpID mismatch, wrong public key for the credential, or a tampered signature.
Common situations: rpID or origin misconfigured between environments (localhost vs production domain); challenge cookie expired or cleared before verification; multiple transports altering the assertion bytes; clock/session issues invalidating the stored challenge.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- WebAuthn challenge was missing
- WebAuthn registration response could not be verified
- Authenticator not found.
- Authenticator not found.
- Authenticator not found.
AI-assisted analysis of nextauthjs/next-auth@a1a16a5a77 (2026-08-28).
Data as JSON: /api/errors/b84eb4cc28175946.
Report an issue: GitHub.