Better Auth Credentials Plugin

0.5.2 · active · verified Wed Apr 22

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.

Common errors

Warnings

Install

Imports

Quickstart

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.

import { betterAuth } from "better-auth";
import { credentials } from "better-auth-credentials-plugin";

// --- Server-side configuration (e.g., in auth.ts) ---
export const auth = betterAuth({
    // ... other Better Auth configurations ...
    // Disable default email and password if this plugin replaces it for a specific flow
    emailAndPassword: {
        enabled: false,
    },
    plugins: [
        credentials({
            autoSignUp: true, // Automatically create a new user if not found
            async callback(ctx, parsed) {
                // 'parsed' contains the validated input credentials (e.g., username, password)
                // Implement your external authentication logic here (e.g., LDAP, external API)
                const { email, password } = parsed;

                // Example: Authenticating against a hypothetical external API
                const externalAuthServiceUrl = process.env.EXTERNAL_AUTH_SERVICE_URL ?? 'http://localhost:4000/login';
                const response = await fetch(externalAuthServiceUrl, {
                    method: "POST",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({ email, password }),
                });

                if (!response.ok) {
                    // Handle authentication failure from the external system
                    const errorData = await response.json().catch(() => ({ message: 'Authentication failed' }));
                    throw new Error(errorData.message || 'Invalid credentials');
                }

                const { token, user: apiUser } = await response.json();

                // Return user data, including a unique 'email' field, to Better Auth.
                // This data will be used to create/update the user and link the account.
                return {
                    // 'email' is mandatory for Better Auth user linking/creation
                    email: apiUser.email,
                    // Additional fields to store on the user or account (e.g., token, name)
                    name: apiUser.name,
                    externalAuthToken: token,
                };
            },
        }),
    ],
});

// --- Client-side usage (e.g., in authClient.ts) ---
// Requires 'better-auth/client' and '/client' subpath for credentialsClient
// import { createAuthClient } from 'better-auth/client';
// import { credentialsClient } from 'better-auth-credentials-plugin/client';

// const authClient = createAuthClient({
//     baseURL: "/api/auth",
//     plugins: [
//         // If you customized the path or schema, you'd pass generic types here
//         credentialsClient(),
//     ],
// });

view raw JSON →