{"id":16594,"library":"better-auth-credentials-plugin","title":"Better Auth Credentials Plugin","description":"The Better Auth Credentials Plugin provides a highly customizable mechanism for authenticating users against external systems like LDAP, custom APIs, or other credential-based services, integrating seamlessly with the Better Auth ecosystem. It is currently at version 0.5.2 and appears to have a relatively active release cadence, with several minor releases in recent months addressing bug fixes and compatibility. Key differentiators include full control over the authentication callback logic, optional auto sign-up, management of account linking and session creation, and flexible route customization with Zod schemas for validation and OpenAPI documentation. It's designed to complement, not replace, Better Auth's native email/password or username flows when integrating with third-party authentication sources. The plugin explicitly supports both server and client-side integration.","status":"active","version":"0.5.2","language":"javascript","source_language":"en","source_url":"https://github.com/erickweil/better-auth-credentials-plugin","tags":["javascript","better-auth","betterauth","auth","authentication","credentials","ldap","active-directory","ad","typescript"],"install":[{"cmd":"npm install better-auth-credentials-plugin","lang":"bash","label":"npm"},{"cmd":"yarn add better-auth-credentials-plugin","lang":"bash","label":"yarn"},{"cmd":"pnpm add better-auth-credentials-plugin","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Required for defining input schemas for validation and API documentation.","package":"@standard-schema/spec","optional":false},{"reason":"Core dependency as this is a plugin for Better Auth. Version >=1.5.0 is recommended due to internal API changes.","package":"better-auth","optional":false},{"reason":"Used for schema definition and validation. Supports both v3 and v4, but compatibility with Better Auth version must be considered.","package":"zod","optional":false}],"imports":[{"note":"This is the main server-side plugin function for configuring credential authentication. The package is ESM-first, commonjs `require` syntax may not work directly without transpilation or bundler configuration.","wrong":"const credentials = require('better-auth-credentials-plugin');","symbol":"credentials","correct":"import { credentials } from 'better-auth-credentials-plugin';"},{"note":"For client-side usage, particularly with bundlers like Webpack or Turbopack, you must use the `/client` subpath import to prevent server-side dependencies from being included in the client bundle. This was addressed in v0.4.0.","wrong":"import { credentialsClient } from 'better-auth-credentials-plugin';","symbol":"credentialsClient","correct":"import { credentialsClient } from 'better-auth-credentials-plugin/client';"},{"note":"Provides a default Zod schema for credentials, often used in conjunction with `credentialsClient` on the frontend.","symbol":"defaultCredentialsSchema","correct":"import { defaultCredentialsSchema } from 'better-auth-credentials-plugin/client';"}],"quickstart":{"code":"import { betterAuth } from \"better-auth\";\nimport { credentials } from \"better-auth-credentials-plugin\";\n\n// --- Server-side configuration (e.g., in auth.ts) ---\nexport const auth = betterAuth({\n    // ... other Better Auth configurations ...\n    // Disable default email and password if this plugin replaces it for a specific flow\n    emailAndPassword: {\n        enabled: false,\n    },\n    plugins: [\n        credentials({\n            autoSignUp: true, // Automatically create a new user if not found\n            async callback(ctx, parsed) {\n                // 'parsed' contains the validated input credentials (e.g., username, password)\n                // Implement your external authentication logic here (e.g., LDAP, external API)\n                const { email, password } = parsed;\n\n                // Example: Authenticating against a hypothetical external API\n                const externalAuthServiceUrl = process.env.EXTERNAL_AUTH_SERVICE_URL ?? 'http://localhost:4000/login';\n                const response = await fetch(externalAuthServiceUrl, {\n                    method: \"POST\",\n                    headers: { \"Content-Type\": \"application/json\" },\n                    body: JSON.stringify({ email, password }),\n                });\n\n                if (!response.ok) {\n                    // Handle authentication failure from the external system\n                    const errorData = await response.json().catch(() => ({ message: 'Authentication failed' }));\n                    throw new Error(errorData.message || 'Invalid credentials');\n                }\n\n                const { token, user: apiUser } = await response.json();\n\n                // Return user data, including a unique 'email' field, to Better Auth.\n                // This data will be used to create/update the user and link the account.\n                return {\n                    // 'email' is mandatory for Better Auth user linking/creation\n                    email: apiUser.email,\n                    // Additional fields to store on the user or account (e.g., token, name)\n                    name: apiUser.name,\n                    externalAuthToken: token,\n                };\n            },\n        }),\n    ],\n});\n\n// --- Client-side usage (e.g., in authClient.ts) ---\n// Requires 'better-auth/client' and '/client' subpath for credentialsClient\n// import { createAuthClient } from 'better-auth/client';\n// import { credentialsClient } from 'better-auth-credentials-plugin/client';\n\n// const authClient = createAuthClient({\n//     baseURL: \"/api/auth\",\n//     plugins: [\n//         // If you customized the path or schema, you'd pass generic types here\n//         credentialsClient(),\n//     ],\n// });","lang":"typescript","description":"This quickstart demonstrates the server-side setup for the credentials plugin within a Better Auth instance, showing how to implement a custom authentication callback to verify user credentials against an external API. It also highlights the necessary client-side import pattern."},"warnings":[{"fix":"Ensure your `better-auth` peer dependency is updated to `^1.5.0` or newer, as specified in the plugin's `peerDependencies`.","message":"The `internalAdapter` signature within Better Auth changed in v1.4.0. Upgrading to `better-auth-credentials-plugin` v0.4.0 and higher requires `better-auth` >=1.4.0 to maintain compatibility.","severity":"breaking","affected_versions":">=0.4.0"},{"fix":"Change client-side imports from `import { credentialsClient } from 'better-auth-credentials-plugin';` to `import { credentialsClient } from 'better-auth-credentials-plugin/client';`","message":"When using bundlers like Webpack, Turbopack, or Vite, the client-side module `credentialsClient` must be imported via the dedicated subpath `better-auth-credentials-plugin/client`. Failing to do so can result in server-side dependencies being bundled into client code, leading to errors or unnecessarily large bundles.","severity":"gotcha","affected_versions":">=0.4.0"},{"fix":"Ensure your `callback` function always returns an object containing a unique `email` property (e.g., `{ email: 'user@example.com', ...otherUserData }`).","message":"The credentials callback *must* return an `email` field as part of the user data. This email is crucial for Better Auth to create or update the user in the database and link the account with the session. If `autoSignUp` is enabled and no `email` is returned, user creation will fail.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"For standard password-based authentication, use Better Auth's built-in `emailAndPassword` or `username` plugins. Only use `better-auth-credentials-plugin` for integration with *external* credential systems like LDAP or custom APIs.","message":"This plugin is not intended for re-implementing standard email and password login by storing hashed passwords in your database. Using it this way would lead to redundant database lookups and is less efficient than Better Auth's native `emailAndPassword` or `username` plugins.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Consider setting a unique `providerId` in the plugin configuration (e.g., `credentials({ providerId: 'ldap', ... })`) and enabling `linkAccountIfExisting: true` if you want users to link multiple authentication methods to a single Better Auth account.","message":"When integrating with Better Auth's default `emailAndPassword` or `username` flows, accounts created via the credentials plugin will not automatically be able to log in with email/password (as no password is set). To allow users to log in with both methods, configure a custom `providerId` for this plugin and set `linkAccountIfExisting: true`.","severity":"gotcha","affected_versions":">=0.1.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Update your `better-auth` package to version `^1.5.0` or higher to match the plugin's requirements. Run `npm install better-auth@latest`.","cause":"This typically occurs when `better-auth-credentials-plugin` is used with an older version of `better-auth` that does not match the plugin's expected `internalAdapter` API signature.","error":"TypeError: Cannot read properties of undefined (reading 'internalAdapter')"},{"fix":"Ensure your `callback` function returns an object with at least a valid `email` property. If using a custom `inputSchema`, verify the incoming `parsed` object from the client matches its requirements.","cause":"The credentials `callback` did not return a required `email` field, or the `inputSchema` (if custom) was not satisfied by the incoming credentials.","error":"Error: ZodError: [ { \"code\": \"invalid_type\", \"expected\": \"string\", \"received\": \"undefined\", \"path\": [ \"email\" ], \"message\": \"Email is required\" } ]"},{"fix":"For client-side code, ensure you are importing from the `/client` subpath: `import { credentialsClient } from 'better-auth-credentials-plugin/client';`. Also, check that `better-auth-credentials-plugin` is correctly installed.","cause":"This error, particularly in a client-side bundle, often means the bundler is trying to import the server-side entrypoint or the subpath import is incorrect for the client.","error":"Module not found: Error: Can't resolve 'better-auth-credentials-plugin'"},{"fix":"Ensure your project is configured for ESM. Use `import { credentials } from 'better-auth-credentials-plugin';` instead of `const credentials = require('better-auth-credentials-plugin');`. If using a bundler, verify its configuration for resolving ESM packages.","cause":"Attempting to use CommonJS `require()` syntax in an ESM project, or a bundler configuration issue where `better-auth-credentials-plugin` is treated as CommonJS.","error":"TypeError: require is not a function in ES module scope"}],"ecosystem":"npm"}