nextauthjs/next-auth · error · AuthError
Invalid WebAuthn Authentication response
Error message
Invalid WebAuthn Authentication response
What it means
verifyAuthenticate validates the WebAuthn assertion response shape before verification. It throws when the response data is missing, not an object, or lacks a string `id` property (the credential ID). The ID is required to normalize (base64url round-trip) and look up the authenticator.
Source
Thrown at packages/core/src/lib/utils/webauthn-utils.ts:221
export async function verifyAuthenticate(
options: InternalOptionsWebAuthn,
request: RequestInternal,
resCookies: Cookie[]
): Promise<{ account: AdapterAccount; user: User }> {
const { adapter, provider } = options
// Get WebAuthn response from request body
const data =
request.body && typeof request.body.data === "string"
? (JSON.parse(request.body.data) as unknown)
: undefined
if (
!data ||
typeof data !== "object" ||
!("id" in data) ||
typeof data.id !== "string"
) {
throw new AuthError("Invalid WebAuthn Authentication response")
}
// Reset the ID so we smooth out implementation differences
const credentialID = toBase64(fromBase64(data.id))
// Get authenticator from database
const authenticator = await adapter.getAuthenticator(credentialID)
if (!authenticator) {
throw new AuthError(
`WebAuthn authenticator not found in database: ${JSON.stringify({
credentialID,
})}`
)
}
// Get challenge from request cookies
const { challenge: expectedChallenge } = await webauthnChallenge.use(
options,View on GitHub (pinned to a1a16a5a77)
Solutions
- Ensure the client sends the full assertion including the string `id` field from navigator.credentials.get()
- Verify the server parses the request body as JSON before passing data to verifyAuthenticate
- Log the incoming data to confirm the shape and that `id` is present
- If using a custom client, map its credential field to `id` before sending
Example fix
// before await verifyAuthenticate(request.body.text) // raw string, no id // after const data = JSON.parse(request.body) if (data?.id) await verifyAuthenticate(data)
Defensive patterns
Strategy: type-guard
Validate before calling
const data = await request.json()
if (!data || typeof data !== 'object' || typeof data.id !== 'string') {
return new Response('Invalid WebAuthn response', { status: 400 })
} Type guard
function isValidAssertion(d: unknown): d is { id: string; [k: string]: unknown } {
return !!d && typeof d === 'object' && 'id' in d && typeof (d as any).id === 'string'
} Try / catch
try {
await verifyAuthenticate(data)
} catch (e) {
if (e instanceof AuthError && /Invalid WebAuthn Authentication response/.test(e.message)) {
// return 400 and ask client to retry the ceremony
}
} Prevention
- Always JSON-parse the body before verification
- Use the library's official client helper to build assertion payloads
- Log malformed payloads during development
- Add a schema check (e.g. zod) on the webhook/route input
When it happens
Trigger: Calling verifyAuthenticate (via the `verified` action) with response data that is null, not an object, or whose `id` is not a string — e.g. a malformed client payload or a body-parsing step that dropped the id.
Common situations: Client sends an empty or truncated assertion; a custom client library returns id under a different key; request body parsed as text instead of JSON; browser API version differences changing field names.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Invalid WebAuthn Registration response
- Authenticator not found.
- No user id.
- Authenticator not found.
- No user id.
AI-assisted analysis of nextauthjs/next-auth@a1a16a5a77 (2026-08-28).
Data as JSON: /api/errors/13358ebdc834adab.
Report an issue: GitHub.