> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/better-auth/better-auth/llms.txt
> Use this file to discover all available pages before exploring further.

# Email & Password

> Set up email and password authentication with sign-up, sign-in, email verification, and password reset.

Email and password authentication is built into Better Auth. Enable it with a single config option, then use the client methods to sign users up, sign them in, and manage passwords.

<Note>
  If you prefer username-based login, see the [username plugin](/authentication/username). It extends email/password auth with username support.
</Note>

## Enable email and password

Set `emailAndPassword.enabled` to `true` in your `betterAuth` config:

```ts title="auth.ts" theme={null}
import { betterAuth } from "better-auth";

export const auth = betterAuth({
  emailAndPassword: {
    enabled: true,
  },
});
```

## Sign up

Call `signUp.email` on the client with the user's details:

```ts title="sign-up.ts" theme={null}
import { authClient } from "@/lib/auth-client";

const { data, error } = await authClient.signUp.email({
  name: "John Doe",
  email: "john.doe@example.com",
  password: "password1234", // min 8 characters, max 128 by default
  image: "https://example.com/avatar.png", // optional
  callbackURL: "/dashboard", // redirect after email verification (optional)
}, {
  onRequest: () => {
    // show loading state
  },
  onSuccess: () => {
    // redirect or show success
  },
  onError: (ctx) => {
    alert(ctx.error.message);
  },
});
```

### Auto sign-in after sign-up

By default, users are automatically signed in after a successful sign-up. Disable this with `autoSignIn: false`:

```ts title="auth.ts" theme={null}
export const auth = betterAuth({
  emailAndPassword: {
    enabled: true,
    autoSignIn: false, // defaults to true
  },
});
```

<Warning>
  When `autoSignIn` is `false` or `requireEmailVerification` is `true`, the sign-up endpoint returns a generic success response for existing emails to prevent email enumeration.
</Warning>

## Sign in

Call `signIn.email` on the client:

```ts title="sign-in.ts" theme={null}
import { authClient } from "@/lib/auth-client";

const { data, error } = await authClient.signIn.email({
  email: "john.doe@example.com",
  password: "password1234",
  rememberMe: true,    // keep session after browser closes (default: true)
  callbackURL: "/dashboard", // optional redirect
});
```

<Warning>
  Always call client methods from the client side. Never call them from the server.
</Warning>

### Server-side sign-in

To authenticate a user on the server, use `auth.api`:

```ts title="server.ts" theme={null}
import { auth } from "./auth";

const response = await auth.api.signInEmail({
  body: {
    email: "john.doe@example.com",
    password: "password1234",
  },
  asResponse: true, // returns a Response object so cookies are set
});
```

## Sign out

Call `signOut` on the client:

```ts title="user-card.ts" theme={null}
import { authClient } from "@/lib/auth-client";

await authClient.signOut({
  fetchOptions: {
    onSuccess: () => {
      router.push("/login");
    },
  },
});
```

## Email verification

Provide a `sendVerificationEmail` function in your auth config. Better Auth calls it whenever a verification email needs to be sent:

```ts title="auth.ts" theme={null}
import { betterAuth } from "better-auth";
import { sendEmail } from "./email"; // your email sending function

export const auth = betterAuth({
  emailVerification: {
    sendVerificationEmail: async ({ user, url, token }, request) => {
      void sendEmail({
        to: user.email,
        subject: "Verify your email address",
        text: `Click the link to verify your email: ${url}`,
      });
    },
  },
});
```

<Warning>
  Do not `await` the email sending call. Awaiting it can introduce timing attacks. On serverless platforms, use `waitUntil` to ensure the email is sent before the function exits.
</Warning>

### Require email verification before sign-in

Set `requireEmailVerification: true` to block sign-in until the email is confirmed:

```ts title="auth.ts" theme={null}
export const auth = betterAuth({
  emailAndPassword: {
    enabled: true,
    requireEmailVerification: true,
  },
});
```

Handle the error on the client:

```ts title="sign-in.ts" theme={null}
await authClient.signIn.email(
  { email: "user@example.com", password: "password" },
  {
    onError: (ctx) => {
      if (ctx.error.status === 403) {
        alert("Please verify your email address before signing in.");
      }
    },
  }
);
```

### Trigger verification manually

```ts title="resend-verification.ts" theme={null}
import { authClient } from "@/lib/auth-client";

await authClient.sendVerificationEmail({
  email: "user@email.com",
  callbackURL: "/",
});
```

## Password reset

### Configure the server

Provide a `sendResetPassword` function in your `emailAndPassword` config:

```ts title="auth.ts" theme={null}
import { betterAuth } from "better-auth";
import { sendEmail } from "./email";

export const auth = betterAuth({
  emailAndPassword: {
    enabled: true,
    sendResetPassword: async ({ user, url, token }, request) => {
      void sendEmail({
        to: user.email,
        subject: "Reset your password",
        text: `Click the link to reset your password: ${url}`,
      });
    },
    onPasswordReset: async ({ user }, request) => {
      console.log(`Password for ${user.email} has been reset.`);
    },
  },
});
```

### Request a password reset

Call `requestPasswordReset` on the client with the user's email:

```ts title="forgot-password.ts" theme={null}
import { authClient } from "@/lib/auth-client";

await authClient.requestPasswordReset({
  email: "john.doe@example.com",
  redirectTo: "/reset-password", // your reset password page URL
});
```

When the user clicks the link in the email they are redirected to `redirectTo` with a `?token=...` query parameter. If the token is invalid or expired, the redirect includes `?error=INVALID_TOKEN`.

### Reset the password

On your reset password page, read the token from the URL and call `resetPassword`:

```ts title="reset-password.ts" theme={null}
import { authClient } from "@/lib/auth-client";

const token = new URLSearchParams(window.location.search).get("token");

if (token) {
  const { data, error } = await authClient.resetPassword({
    newPassword: "newPassword1234",
    token,
  });
}
```

### Change password (authenticated)

Authenticated users can change their password directly:

```ts title="change-password.ts" theme={null}
import { authClient } from "@/lib/auth-client";

await authClient.changePassword({
  currentPassword: "oldPassword1234",
  newPassword: "newPassword1234",
  revokeOtherSessions: true, // invalidate other active sessions
});
```

## Configuration reference

| Option                          | Type       | Default | Description                                  |
| ------------------------------- | ---------- | ------- | -------------------------------------------- |
| `enabled`                       | `boolean`  | `false` | Enable email and password authentication.    |
| `autoSignIn`                    | `boolean`  | `true`  | Automatically sign in after sign-up.         |
| `requireEmailVerification`      | `boolean`  | `false` | Block sign-in until email is verified.       |
| `minPasswordLength`             | `number`   | `8`     | Minimum password length.                     |
| `maxPasswordLength`             | `number`   | `128`   | Maximum password length.                     |
| `disableSignUp`                 | `boolean`  | `false` | Disable email/password sign-up.              |
| `sendResetPassword`             | `function` | —       | Send a password reset email.                 |
| `onPasswordReset`               | `function` | —       | Callback after a successful password reset.  |
| `resetPasswordTokenExpiresIn`   | `number`   | `3600`  | Reset token lifetime in seconds.             |
| `revokeSessionsOnPasswordReset` | `boolean`  | `false` | Revoke all other sessions on password reset. |
