nextauthjs/next-auth · error · WebAuthnVerificationError

WebAuthn registration response could not be verified

Error message

WebAuthn registration response could not be verified

What it means

The attestation response shape and challenge data were accepted, but @simplewebauthn/server's verifyRegistrationResponse returned verified:false or missing registrationInfo, so the registration cannot be trusted. Thrown as a WebAuthnVerificationError.

Source

Thrown at packages/core/src/lib/utils/webauthn-utils.ts:367

  // Verify the response
  let verification: VerifiedRegistrationResponse
  try {
    const relayingParty = provider.getRelayingParty(options, request)
    verification = await provider.simpleWebAuthn.verifyRegistrationResponse({
      ...provider.verifyRegistrationOptions,
      expectedChallenge,
      response: data as RegistrationResponseJSON,
      expectedOrigin: relayingParty.origin,
      expectedRPID: relayingParty.id,
    })
  } catch (e: any) {
    throw new WebAuthnVerificationError(e)
  }

  // Make sure the response was verified
  if (!verification.verified || !verification.registrationInfo) {
    throw new WebAuthnVerificationError(
      "WebAuthn registration response could not be verified"
    )
  }

  // Build a new account
  const account = {
    providerAccountId: toBase64(verification.registrationInfo.credentialID),
    provider: options.provider.id,
    type: provider.type,
  }

  // Build a new authenticator
  const authenticator = {
    providerAccountId: account.providerAccountId,
    counter: verification.registrationInfo.counter,
    credentialID: toBase64(verification.registrationInfo.credentialID),
    credentialPublicKey: toBase64(
      verification.registrationInfo.credentialPublicKey

View on GitHub (pinned to a1a16a5a77)

Solutions

  1. Align WebAuthnProvider rpID and origin with the actual client origin
  2. Ensure the challenge cookie from startRegistration is intact and unchanged at verify time
  3. Check @simplewebauthn/server version supports the client's attestation format
  4. Test on a platform/browser that supports the configured authenticatorSelection requirements

Example fix

// before
WebAuthnProvider({ id: "prod.example.com" }) // testing on localhost
// after
WebAuthnProvider({ id: "localhost", origin: "http://localhost:3000" })
Defensive patterns

Strategy: try-catch

Validate before calling

// environment pre-check
console.assert(provider.rpID === location.hostname, 'rpID must match the client origin')
console.assert(document.cookie.includes('next-auth.webauthn-challenge'), 'challenge cookie must exist')

Try / catch

try {
  await verifyRegister(data)
} catch (e) {
  if (e instanceof WebAuthnVerificationError) {
    // clear cookies, log attestation failure, restart registration
    return new Response('Attestation verification failed', { status: 400 })
  }
  throw e
}

Prevention

When it happens

Trigger: verifyRegister receives an attestation that fails verification — challenge mismatch with the cookie, origin/rpID mismatch, unsupported attestation format, or device not eligible for passkey creation.

Common situations: rpID/origin configured for a different domain than the client; challenge cookie expired or replaced between start and verify; attestation format (e.g. 'none' vs 'packed') unsupported by the @simplewebauthn/server version; browser/platform restrictions (e.g. no platform authenticator available).

Related errors


AI-assisted analysis of nextauthjs/next-auth@a1a16a5a77 (2026-08-28). Data as JSON: /api/errors/f92039e72a436a5d. Report an issue: GitHub.