Skip to content
Back to skills

051 Email A96376f5

ASecurity

Email/password is built-in auth method in Better Auth. No plugins required for basic functionality.

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
developmentgonextjsnodeexpressapisecurity

Works with

  • cli
  • api

Security analysis

A100/100

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 051-email_a96376f5 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 051 Email A96376f5?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 051 Email A96376f5
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-051-email-a96376f5/badge)](https://www.skillsdirectory.com/skills/tools-only-051-email-a96376f5)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
# Email/Password Authentication

Email/password is built-in auth method in Better Auth. No plugins required for basic functionality.

## Server Configuration

### Basic Setup

```ts
import { betterAuth } from "better-auth";

export const auth = betterAuth({
  emailAndPassword: {
    enabled: true,
    autoSignIn: true, // Auto sign-in after signup (default: true)
    requireEmailVerification: false, // Require email verification before login
    sendResetPasswordToken: async ({ user, url }) => {
      // Send password reset email
      await sendEmail(user.email, url);
    }
  }
});
```

### Custom Password Requirements

```ts
export const auth = betterAuth({
  emailAndPassword: {
    enabled: true,
    password: {
      minLength: 8,
      requireUppercase: true,
      requireLowercase: true,
      requireNumbers: true,
      requireSpecialChars: true
    }
  }
});
```

## Client Usage

### Sign Up

```ts
import { authClient } from "@/lib/auth-client";

const { data, error } = await authClient.signUp.email({
  email: "user@example.com",
  password: "securePassword123",
  name: "John Doe",
  image: "https://example.com/avatar.jpg", // optional
  callbackURL: "/dashboard" // optional
}, {
  onSuccess: (ctx) => {
    // ctx.data contains user and session
    console.log("User created:", ctx.data.user);
  },
  onError: (ctx) => {
    alert(ctx.error.message);
  }
});
```

### Sign In

```ts
const { data, error } = await authClient.signIn.email({
  email: "user@example.com",
  password: "securePassword123",
  callbackURL: "/dashboard",
  rememberMe: true // default: true
}, {
  onSuccess: () => {
    // redirect or update UI
  },
  onError: (ctx) => {
    console.error(ctx.error.message);
  }
});
```

### Sign Out

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

## Email Verification

### Server Setup

```ts
export const auth = betterAuth({
  emailVerification: {
    sendVerificationEmail: async ({ user, url, token }) => {
      // Send verification email
      await sendEmail({
        to: user.email,
        subject: "Verify your email",
        html: `Click <a href="${url}">here</a> to verify your email.`
      });
    },
    sendOnSignUp: true, // Send verification email on signup
    autoSignInAfterVerification: true // Auto sign-in after verification
  },
  emailAndPassword: {
    enabled: true,
    requireEmailVerification: true // Require verification before login
  }
});
```

### Client Usage

```ts
// Send verification email
await authClient.sendVerificationEmail({
  email: "user@example.com",
  callbackURL: "/verify-success"
});

// Verify email with token
await authClient.verifyEmail({
  token: "verification-token-from-email"
});
```

## Password Reset Flow

### Server Setup

```ts
export const auth = betterAuth({
  emailAndPassword: {
    enabled: true,
    sendResetPasswordToken: async ({ user, url, token }) => {
      await sendEmail({
        to: user.email,
        subject: "Reset your password",
        html: `Click <a href="${url}">here</a> to reset your password.`
      });
    }
  }
});
```

### Client Flow

```ts
// Step 1: Request password reset
await authClient.forgetPassword({
  email: "user@example.com",
  redirectTo: "/reset-password"
});

// Step 2: Reset password with token
await authClient.resetPassword({
  token: "reset-token-from-email",
  password: "newSecurePassword123"
});
```

### Change Password (Authenticated)

```ts
await authClient.changePassword({
  currentPassword: "oldPassword123",
  newPassword: "newPassword456",
  revokeOtherSessions: true // Optional: logout other sessions
});
```

## Username Authentication

Requires `username` plugin for username-based auth.

### Server Setup

```ts
import { betterAuth } from "better-auth";
import { username } from "better-auth/plugins";

export const auth = betterAuth({
  plugins: [
    username({
      // Allow sign in with username or email
      allowUsernameOrEmail: true
    })
  ]
});
```

### Client Setup

```ts
import { createAuthClient } from "better-auth/client";
import { usernameClient } from "better-auth/client/plugins";

export const authClient = createAuthClient({
  plugins: [usernameClient()]
});
```

### Client Usage

```ts
// Sign up with username
await authClient.signUp.username({
  username: "johndoe",
  password: "securePassword123",
  email: "john@example.com", // optional
  name: "John Doe"
});

// Sign in with username
await authClient.signIn.username({
  username: "johndoe",
  password: "securePassword123"
});

// Sign in with username or email (if allowUsernameOrEmail: true)
await authClient.signIn.username({
  username: "johndoe", // or "john@example.com"
  password: "securePassword123"
});
```

## Framework Setup

### Next.js (App Router)

```ts
// app/api/auth/[...all]/route.ts
import { auth } from "@/lib/auth";
import { toNextJsHandler } from "better-auth/next-js";

export const { POST, GET } = toNextJsHandler(auth);
```

### Next.js (Pages Router)

```ts
// pages/api/auth/[...all].ts
import { auth } from "@/lib/auth";
import { toNextJsHandler } from "better-auth/next-js";

export default toNextJsHandler(auth);
```

### Nuxt

```ts
// server/api/auth/[...all].ts
import { auth } from "~/utils/auth";
import { toWebRequest } from "better-auth/utils/web";

export default defineEventHandler((event) => {
  return auth.handler(toWebRequest(event));
});
```

### SvelteKit

```ts
// hooks.server.ts
import { auth } from "$lib/auth";
import { svelteKitHandler } from "better-auth/svelte-kit";

export async function handle({ event, resolve }) {
  return svelteKitHandler({ event, resolve, auth });
}
```

### Astro

```ts
// pages/api/auth/[...all].ts
import { auth } from "@/lib/auth";

export async function ALL({ request }: { request: Request }) {
  return auth.handler(request);
}
```

### Hono

```ts
import { Hono } from "hono";
import { auth } from "./auth";

const app = new Hono();

app.on(["POST", "GET"], "/api/auth/*", (c) => {
  return auth.handler(c.req.raw);
});
```

### Express

```ts
import express from "express";
import { toNodeHandler } from "better-auth/node";
import { auth } from "./auth";

const app = express();

app.all("/api/auth/*", toNodeHandler(auth));
```

## Protected Routes

### Next.js Middleware

```ts
// middleware.ts
import { auth } from "@/lib/auth";
import { NextRequest, NextResponse } from "next/server";

export async function middleware(request: NextRequest) {
  const session = await auth.api.getSession({
    headers: request.headers
  });

  if (!session) {
    return NextResponse.redirect(new URL("/login", request.url));
  }

  return NextResponse.next();
}

export const config = {
  matcher: ["/dashboard/:path*", "/profile/:path*"]
};
```

### SvelteKit Hooks

```ts
// hooks.server.ts
import { auth } from "$lib/auth";
import { redirect } from "@sveltejs/kit";

export async function handle({ event, resolve }) {
  const session = await auth.api.getSession({
    headers: event.request.headers
  });

  if (event.url.pathname.startsWith("/dashboard") && !session) {
    throw redirect(303, "/login");
  }

  return resolve(event);
}
```

### Nuxt Middleware

```ts
// middleware/auth.ts
export default defineNuxtRouteMiddleware(async (to) => {
  const { data: session } = await useAuthSession();

  if (!session.value && to.path.startsWith("/dashboard")) {
    return navigateTo("/login");
  }
});
```

## User Profile Management

### Get Current User

```ts
const { data: session } = await authClient.getSession();
console.log(session.user);
```

### Update User Profile

```ts
await authClient.updateUser({
  name: "New Name",
  image: "https://example.com/new-avatar.jpg",
  // Custom fields if defined in schema
});
```

### Delete User Account

```ts
await authClient.deleteUser({
  password: "currentPassword", // Required for security
  callbackURL: "/" // Redirect after deletion
});
```

## Best Practices

1. **Password Security**: Enforce strong password requirements
2. **Email Verification**: Enable for production to prevent spam
3. **Rate Limiting**: Prevent brute force attacks (see advanced-features.md)
4. **HTTPS**: Always use HTTPS in production
5. **Error Messages**: Don't reveal if email exists during login
6. **Session Security**: Use secure, httpOnly cookies
7. **CSRF Protection**: Better Auth handles this automatically
8. **Password Reset**: Set short expiration for reset tokens
9. **Account Lockout**: Consider implementing after N failed attempts
10. **Audit Logs**: Track auth events for security monitoring

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.