Authentication is one of those features that every application needs, but building it from scratch is time-consuming and error-prone. I've tried many authentication solutions over the years, and Better Auth stands out for its simplicity, type safety, and flexibility. It handles sessions, password hashing, and all the edge cases automatically, while giving you full control over the implementation.
Better Auth is a modern, type-safe authentication library that simplifies user authentication in Node.js and React applications. In this guide, we'll learn how to implement complete authentication with email/password, session management, and protected routes.
What is Better Auth?
Better Auth is a modern authentication library for Node.js and React applications. It provides:
- Type-safe authentication - Full TypeScript support with autocomplete
- Email/password authentication - Built-in email and password auth
- Session management - Automatic session handling with cookies
- Multiple database adapters - Drizzle ORM, Prisma, and more
- Custom password hashing - Use scrypt, bcrypt, or your own hashing
- OAuth support - Integrate with social providers
- Protected routes - Easy route protection for both client and server
- Production-ready - Designed for SaaS applications
Installation
First, let's install Better Auth and a database adapter:
npm install better-auth
npm install better-auth/adapters/drizzle
For Drizzle ORM (used in this example):
npm install drizzle-orm drizzle-kit
Backend Setup: Auth Configuration
Configure Better Auth with your database adapter and custom password hashing:
import { betterAuth } from 'better-auth';
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
import { db } from './db/index.js';
import * as schema from './db/schema.js';
import { scrypt, randomBytes, timingSafeEqual } from 'crypto';
import { promisify } from 'util';
const scryptAsync = promisify(scrypt);
// Custom password hashing with scrypt
async function hashPassword(password: string): Promise<string> {
const salt = randomBytes(16).toString('hex');
const normalizedPassword = password.normalize('NFKC');
const derivedKey = (await scryptAsync(normalizedPassword, salt, 64, {
N: 16384,
r: 8,
p: 1,
})) as Buffer;
return `${salt}:${derivedKey.toString('hex')}`;
}
async function verifyPassword(data: { hash: string; password: string }): Promise<boolean> {
const [salt, storedKey] = data.hash.split(':');
if (!salt || !storedKey) return false;
const normalizedPassword = data.password.normalize('NFKC');
const derivedKey = (await scryptAsync(normalizedPassword, salt, 64, {
N: 16384,
r: 8,
p: 1,
})) as Buffer;
const storedKeyBuffer = Buffer.from(storedKey, 'hex');
return timingSafeEqual(derivedKey, storedKeyBuffer);
}
export const auth = betterAuth({
secret: process.env.BETTER_AUTH_SECRET!,
baseURL: process.env.BETTER_AUTH_URL!,
basePath: '/api/auth',
database: drizzleAdapter(db, {
provider: 'sqlite',
schema: {
user: schema.users,
session: schema.sessions,
account: schema.accounts,
verification: schema.verifications,
},
}),
emailAndPassword: {
enabled: true,
requireEmailVerification: false,
password: {
hash: hashPassword,
verify: verifyPassword,
},
},
session: {
expiresIn: 60 * 60 * 24 * 7, // 7 days
updateAge: 60 * 60 * 24, // 1 day
},
trustedOrigins: [process.env.FRONTEND_URL!],
});
Express.js Integration
Mount Better Auth routes in your Express server:
import express from 'express';
import { toNodeHandler } from 'better-auth/node';
import { auth } from './lib/auth.js';
import cookieParser from 'cookie-parser';
const app = express();
app.use(express.json());
app.use(cookieParser());
// Mount Better Auth routes
app.all('/api/auth/*', toNodeHandler(auth));
app.listen(3001, () => {
console.log('Server running on http://localhost:3001');
});
Best Practices
- Use strong secrets for authentication
- Configure proper CORS origins
- Set appropriate session expiration
- Use custom password hashing
- Handle errors gracefully
- Protect routes properly
π Read the Complete Guide
This is just a brief overview! The complete guide on my blog includes:
- β React Integration - Using Better Auth in React/Next.js
- β Protected Routes - Client and server route protection
- β Session Management - Working with sessions
- β OAuth Providers - Social authentication
- β Email Verification - Email verification flow
- β Real-world examples from production applications
π Read the full article with all code examples here
What's your experience with Better Auth? Share your tips in the comments! π
For more backend guides, check out my blog covering JWT Authentication, Prisma ORM, Express.js, and more.
Top comments (0)