{"record":{"id":"13358ebdc834adab","repo":"nextauthjs/next-auth","slug":"invalid-webauthn-authentication-response","errorCode":null,"errorMessage":"Invalid WebAuthn Authentication response","messagePattern":"Invalid WebAuthn Authentication response","errorType":"exception","errorClass":"AuthError","httpStatus":null,"severity":"error","filePath":"packages/core/src/lib/utils/webauthn-utils.ts","lineNumber":221,"sourceCode":"export async function verifyAuthenticate(\n  options: InternalOptionsWebAuthn,\n  request: RequestInternal,\n  resCookies: Cookie[]\n): Promise<{ account: AdapterAccount; user: User }> {\n  const { adapter, provider } = options\n\n  // Get WebAuthn response from request body\n  const data =\n    request.body && typeof request.body.data === \"string\"\n      ? (JSON.parse(request.body.data) as unknown)\n      : undefined\n  if (\n    !data ||\n    typeof data !== \"object\" ||\n    !(\"id\" in data) ||\n    typeof data.id !== \"string\"\n  ) {\n    throw new AuthError(\"Invalid WebAuthn Authentication response\")\n  }\n\n  // Reset the ID so we smooth out implementation differences\n  const credentialID = toBase64(fromBase64(data.id))\n\n  // Get authenticator from database\n  const authenticator = await adapter.getAuthenticator(credentialID)\n  if (!authenticator) {\n    throw new AuthError(\n      `WebAuthn authenticator not found in database: ${JSON.stringify({\n        credentialID,\n      })}`\n    )\n  }\n\n  // Get challenge from request cookies\n  const { challenge: expectedChallenge } = await webauthnChallenge.use(\n    options,","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/nextauthjs/next-auth/blob/a1a16a5a7780488c7449feece410033f445d0b31/packages/core/src/lib/utils/webauthn-utils.ts#L203-L239","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nawait verifyAuthenticate(request.body.text) // raw string, no id\n// after\nconst data = JSON.parse(request.body)\nif (data?.id) await verifyAuthenticate(data)","handlingStrategy":"type-guard","validationCode":"const data = await request.json()\nif (!data || typeof data !== 'object' || typeof data.id !== 'string') {\n  return new Response('Invalid WebAuthn response', { status: 400 })\n}","typeGuard":"function isValidAssertion(d: unknown): d is { id: string; [k: string]: unknown } {\n  return !!d && typeof d === 'object' && 'id' in d && typeof (d as any).id === 'string'\n}","tryCatchPattern":"try {\n  await verifyAuthenticate(data)\n} catch (e) {\n  if (e instanceof AuthError && /Invalid WebAuthn Authentication response/.test(e.message)) {\n    // return 400 and ask client to retry the ceremony\n  }\n}","preventionTips":["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"],"tags":["webauthn","input-validation","malformed-response"],"backgroundTag":"invalid-webauthn-response","analyzedSha":"a1a16a5a7780488c7449feece410033f445d0b31","analyzedAt":"2026-08-28T21:52:38.200Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}