{"record":{"id":"bf6369e435e7d6c4","repo":"nextauthjs/next-auth","slug":"an-adapter-is-required-for-the-webauthn-provider","errorCode":null,"errorMessage":"An adapter is required for the WebAuthn provider","messagePattern":"An adapter is required for the WebAuthn provider","errorType":"exception","errorClass":"MissingAdapter","httpStatus":null,"severity":"error","filePath":"packages/core/src/lib/utils/webauthn-utils.ts","lineNumber":489,"sourceCode":"    userDisplayName: user.name ?? undefined,\n    rpID: relayingParty.id,\n    rpName: relayingParty.name,\n    excludeCredentials: authenticators?.map((a) => ({\n      id: fromBase64(a.credentialID),\n      type: \"public-key\",\n      transports: stringToTransports(a.transports),\n    })),\n  })\n}\n\nexport function assertInternalOptionsWebAuthn(\n  options: InternalOptions\n): InternalOptionsWebAuthn {\n  const { provider, adapter } = options\n\n  // Adapter is required for WebAuthn\n  if (!adapter)\n    throw new MissingAdapter(\"An adapter is required for the WebAuthn provider\")\n  // Provider must be WebAuthn\n  if (!provider || provider.type !== \"webauthn\") {\n    throw new InvalidProvider(\"Provider must be WebAuthn\")\n  }\n  // Narrow the options type for typed usage later\n  return { ...options, provider, adapter }\n}\n\nfunction fromAdapterAuthenticator(\n  authenticator: AdapterAuthenticator\n): InternalAuthenticator {\n  return {\n    ...authenticator,\n    credentialDeviceType:\n      authenticator.credentialDeviceType as InternalAuthenticator[\"credentialDeviceType\"],\n    transports: stringToTransports(authenticator.transports),\n    credentialID: fromBase64(authenticator.credentialID),\n    credentialPublicKey: fromBase64(authenticator.credentialPublicKey),","sourceCodeStart":471,"sourceCodeEnd":507,"githubUrl":"https://github.com/nextauthjs/next-auth/blob/a1a16a5a7780488c7449feece410033f445d0b31/packages/core/src/lib/utils/webauthn-utils.ts#L471-L507","documentation":"Auth.js throws MissingAdapter when the WebAuthn passkey provider is configured but no database adapter is supplied. The WebAuthn provider must persist credentials (authenticators) and challenges, so an adapter (Prisma, Drizzle, MongoDB, etc.) is mandatory. assertInternalOptionsWebAuthn validates this early when building the WebAuthn route handlers.","triggerScenarios":"Calling localOptions or narrowOptions (which call assertInternalOptionsWebAuthn) with an InternalOptions object whose `adapter` property is undefined/missing while provider.type is \"webauthn\" — e.g. building the WebAuthn provider route handlers without an adapter in the Auth.js config.","commonSituations":"Using the Passkey/WebAuthn provider in a credentials-only setup with no database; forgetting to pass `adapter` when manually constructing options; an adapter plugin failing to initialize (e.g. missing DATABASE_URL so the adapter is never created); upgrading Auth.js and a previously implicit adapter wiring is now explicit.","solutions":["Add a database adapter to your Auth.js config (e.g. `adapter: PrismaAdapter(prisma)`) — WebAuthn credentials cannot work without persistent storage.","Verify your adapter actually initializes: check DATABASE_URL / connection env vars so the adapter isn't undefined at runtime.","Confirm you are using an adapter that supports WebAuthn tables (Authenticator model); update the adapter package and run its schema push/migrations.","If you don't want a database, do not enable the WebAuthn provider; use a standard credentials/OAuth provider instead."],"exampleFix":"// before\nexport const { handlers, auth, signIn, signOut } = NextAuth({\n  providers: [Passkey()],\n})\n// after\nimport { PrismaAdapter } from \"@auth/prisma-adapter\"\nimport { prisma } from \"@/lib/db\"\n\nexport const { handlers, auth, signIn, signOut } = NextAuth({\n  adapter: PrismaAdapter(prisma),\n  providers: [Passkey()],\n})","handlingStrategy":"validation","validationCode":"if (!options.adapter) {\n  throw new Error(\"WebAuthn provider requires a database adapter in your Auth.js config\")\n}","typeGuard":"function hasAdapter(o: { adapter?: unknown }): o is { adapter: NonNullable<unknown> } {\n  return o.adapter != null\n}","tryCatchPattern":"try {\n  const webAuthnOptions = assertInternalOptionsWebAuthn(options)\n} catch (e) {\n  if (e instanceof MissingAdapter) {\n    throw new ConfigError(\"Add an adapter (e.g. PrismaAdapter) — WebAuthn requires persistent storage\")\n  }\n  throw e\n}","preventionTips":["Always configure an adapter when enabling the WebAuthn/Passkey provider","Add a startup-time config check that fails fast if provider type is webauthn but adapter is missing","Keep adapter packages and their schema migrations in sync with your Auth.js version","Verify DATABASE_URL and adapter initialization in CI before deploying"],"tags":["webauthn","adapter","configuration","database"],"backgroundTag":"missing-database-adapter","analyzedSha":"a1a16a5a7780488c7449feece410033f445d0b31","analyzedAt":"2026-08-28T21:52:38.200Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}