---
title: Email and password
description: Configure email/password sign-up, sign-in, email verification, and password reset.
sidebar:
  order: 6
---

`convex-auth` implements email/password authentication as a native Convex provider. No external auth service is needed.

## Enable

```ts
// convex/auth.ts
import { components } from "./_generated/api";
import { convexAuth, type EmailDraft } from "@vortex-api/convex-auth/convex";

const siteUrl = process.env.CONVEX_SITE_URL?.replace(/\/$/, "");

export const auth = convexAuth({
  component: components.convexAuth,
  emailAndPassword: {
    enabled: true,
    email: {
      from: process.env.EMAIL_FROM_ADDRESS ?? "auth@example.com",
      appOrigin: siteUrl,
      sendEmail: async (draft: EmailDraft) => {
        // production: call Resend/Postmark/SES
        console.log(draft);
        return "email-id";
      },
      sendOnSignUp: true,
      sendOnSignIn: false,
    },
  },
});
```

`sendEmail` receives an `EmailDraft` with `from`, `to`, `subject`, `html`, and `text`. It must return an id or any truthy string.

## Sign up

```tsx
import { useAuthActions } from "@vortex-api/convex-auth/react";

export function SignUp() {
  const { signUp, isLoading } = useAuthActions();

  async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const formData = new FormData(event.currentTarget);
    await signUp({
      email: formData.get("email") as string,
      password: formData.get("password") as string,
      name: formData.get("name") as string,
    });
  }

  return (
    <form onSubmit={handleSubmit}>
      <input name="name" placeholder="Name" />
      <input name="email" type="email" required />
      <input name="password" type="password" required minLength={8} />
      <button type="submit" disabled={isLoading}>
        Sign up
      </button>
    </form>
  );
}
```

By default the user is signed in immediately. If `requireVerifiedEmail` is `true`, the session is still created but sign-in can be rejected on the next request.

## Sign in

```tsx
import { useAuthActions } from "@vortex-api/convex-auth/react";

export function SignIn() {
  const { signIn, isLoading } = useAuthActions();

  async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    const formData = new FormData(event.currentTarget);
    await signIn({
      email: formData.get("email") as string,
      password: formData.get("password") as string,
      rememberMe: true,
    });
  }
  // ...
}
```

`rememberMe` controls whether the refresh token is persisted across browser restarts.

## Email verification

If `sendOnSignUp: true`, a verification email is sent automatically. The verification link should point to `/api/auth/verify-email` on your Convex site. The user clicks the link, the token is validated, and the browser is redirected to `callbackURL`.

You can also request a new email from the client:

```tsx
const client = useConvexAuthClient();
await client.sendVerificationEmail({ email });
await client.verifyEmail({ query: { token } });
```

## Password reset

Request the reset:

```tsx
const client = useConvexAuthClient();
await client.forgetPassword({ email, redirectTo: "https://your-app/reset" });
```

The email links to `/api/auth/reset-password/:token`. On your reset page, complete the reset:

```tsx
const client = useConvexAuthClient();
await client.resetPassword({ token, newPassword });
```

## Options

See [`docs/configuration.mdx`](/convex-auth/configuration) for the full `emailAndPassword` table, including `requireVerifiedEmail`, `checkBreach`, `rateLimit`, and `revokeSessionsOnPasswordReset`.
