Initial commit
This commit is contained in:
416
skills/better-auth/references/email-password-auth.md
Normal file
416
skills/better-auth/references/email-password-auth.md
Normal file
@@ -0,0 +1,416 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user